﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PlanProd.Contracts;
using PlanProd.Data;
using PlanProd.Contracts.enums;
using System.Transactions;
using PlanProd.Contracts.Validation;
using System.Linq.Expressions;
using PlanProd.Contracts.Search;
using System.Globalization;
using Web.Framework.Svc;
using Web.Framework.Encrypt;
using Web.Framework.Mapper;
using System.Collections.Specialized;
using PlanProd.InterfaceSAP.ServiceReferenceClasificacionProducto;
using PlanProd.Contracts.Interfaces;
using PlanProd.Services.Clases;
using PlanProd.InterfaceSAP.ServiceReferenceZWSPRODUCTO;

namespace PlanProd.Services
{
    public class PlanProdAdminService : IPlanProdAdmin
    {
        private static string SapSinDatos = "Sin Datos";
        private static string SapNa = "N/A";

        private TransactionScope CreateTransactionScope()
        {
            return new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0, 35, 0));
        }

        public List<ReportingConfiguration> GetReportingConfiguration(string name)
        {
            List<ReportingConfiguration> reportingConfigurationList = new List<ReportingConfiguration>();
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbReporte> query = ctx.DbReportes;
                if (!String.IsNullOrEmpty(name))
                {
                    query = query.Where(r => r.Nombre == name);
                }

                query = query.OrderBy(r => r.MenuOrder);

                foreach (var c in ctx.DbReportes)
                {
                    ReportingConfiguration rc = new ReportingConfiguration();
                    rc.Nombre = c.Nombre;
                    rc.ReportPath = c.ReportPath;
                    rc.ReportUri = c.ReportingServer.Url;
                    rc.UserName = c.ReportingServer.UserName;
                    rc.Password = EncryptHelper.Decrypt(c.ReportingServer.Password, "crm");
                    rc.Domain = c.ReportingServer.Domain;
                    rc.SecurityKey = c.SecurityKey;
                    rc.LocalizationKey = c.LocaleKey;
                    rc.Orden = c.MenuOrder;
                    rc.ReporteGrupoId = c.ReporteGrupoId;
                    reportingConfigurationList.Add(rc);
                }
            }

            return reportingConfigurationList;
        }

        public List<ReporteGrupo> GetReporteGrupo(ServiceOptions serviceOptions, SearchReport search)
        {
            List<ReporteGrupo> reportList = new List<ReporteGrupo>();
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbReporteGrupo> query = ctx.DbReporteGrupoes;
                if (search.Id.HasValue)
                {
                    query = query.Where(t => t.Id == search.Id.Value);
                }
                else
                {
                    query = query.Where(t => t.EmpresaId == search.EmpresaId);

                    if (!String.IsNullOrEmpty(search.Nombre))
                    {
                        query = query.Where(t => t.Nombre.Contains(search.Nombre));
                    }
                }

                foreach (var dbReport in query.ToList())
                {
                    ReporteGrupo report = new ReporteGrupo();
                    EntityMapper.Map(dbReport, report);
                    reportList.Add(report);
                }
            }

            return reportList;
        }

        public List<Report> GetReports(ServiceOptions serviceOptions, SearchReport search)
        {
            List<Report> reportList = new List<Report>();
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbReporte> query = ctx.DbReportes;
                if (search.Id.HasValue)
                {
                    query = query.Where(t => t.Id == search.Id.Value);
                }
                else
                {
                    query = query.Where(t => t.EmpresaId == search.EmpresaId && t.Nombre.Contains(search.Nombre));
                }

                foreach (var dbReport in query.ToList())
                {
                    Report report = new Report();
                    EntityMapper.Map(dbReport, report);
                    reportList.Add(report);
                }
            }

            return reportList;
        }

        public Report SaveReport(ServiceOptions serviceOptions, Report report)
        {
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                DbReporte dbReporte = ctx.DbReportes.Where(r => r.Id == report.Id).SingleOrDefault();
                if (dbReporte == null)
                {
                    dbReporte = new DbReporte();
                    ctx.DbReportes.AddObject(dbReporte);
                }

                EntityMapper.Map(report, dbReporte);
                ctx.SaveChanges();
                report.Id = dbReporte.Id;
                return report;
            }
        }

        public void EliminarReport(ServiceOptions serviceOptions, int reportId)
        {
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                DbReporte dbReporte = ctx.DbReportes.Where(r => r.Id == reportId).SingleOrDefault();
                if (dbReporte != null)
                {
                    ctx.DbReportes.DeleteObject(dbReporte);
                    ctx.SaveChanges();
                }
            }
        }

        public List<ReportServer> GetReportServers(ServiceOptions serviceOptions, SearchReportServer search)
        {
            List<ReportServer> reportList = new List<ReportServer>();
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbReportingServer> query = ctx.DbReportingServers;
                if (search.Id.HasValue)
                {
                    query = query.Where(t => t.Id == search.Id.Value);
                }
                else
                {
                    if (!String.IsNullOrEmpty(search.Url))
                    {
                        query = query.Where(t => t.Url.Contains(search.Url));
                    }
                }

                foreach (var dbReport in query.ToList())
                {
                    ReportServer report = new ReportServer();
                    EntityMapper.Map(dbReport, report);
                    report.Password = string.Empty;
                    reportList.Add(report);
                }
            }

            return reportList;
        }

        public ReportServer SaveReportServer(ServiceOptions serviceOptions, ReportServer reportServer)
        {
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                DbReportingServer dbReporte = ctx.DbReportingServers.Where(r => r.Id == reportServer.Id).SingleOrDefault();
                if (dbReporte == null)
                {
                    dbReporte = new DbReportingServer();
                    ctx.DbReportingServers.AddObject(dbReporte);
                }

                string dbPassword = dbReporte.Password;
                EntityMapper.Map(reportServer, dbReporte);

                if (!String.IsNullOrEmpty(reportServer.Password))
                {
                    dbPassword = EncryptHelper.Encrypt(reportServer.Password, "crm");
                }

                dbReporte.Password = dbPassword;

                ctx.SaveChanges();
                reportServer.Id = dbReporte.Id;
                return reportServer;
            }
        }

        public void EliminarReportServer(ServiceOptions serviceOptions, int reportServerId)
        {
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                DbReportingServer dbReporte = ctx.DbReportingServers.Where(r => r.Id == reportServerId).SingleOrDefault();
                if (dbReporte != null)
                {
                    ctx.DbReportingServers.DeleteObject(dbReporte);
                    ctx.SaveChanges();
                }
            }
        }

        public List<Producto> ActualizarProductosMasivo(ServiceOptions serviceOptions, SearchProductCriteria criteria)
        {
            var result = SearchProducts(serviceOptions, criteria);
            List<Producto> productoList = result.Productos;
            return ActualizarProductos(serviceOptions, productoList, criteria.EmpresaId);

        }

        public List<Producto> ActualizarProductos(ServiceOptions serviceOptions, List<Producto> productos, int empresaId)
        {
            // Obtengo el producto de SAP
            // Empresa
            //-	1 = Lacoste
            //-	2 = Paula
            //-	5 = Penguin
            //-	4 = Cacharel
            // Obligatorio. Valores posibles:
            //-	ARLAC = Lacoste AR
            //-	ARPAU = Paula AR
            //-	ARPEN = Penguin AR 
            //-	ARCAC = Cacharel AR
            //-	BRLAC = Lacoste BR
            //-	CHLAC = Lacoste CH
            //- CHPAU = Paula CH

            string empresaSapId = string.Empty;
            if (empresaId == 1) empresaSapId = "ARLAC";
            else if (empresaId == 2) empresaSapId = "ARPAU";
            else if (empresaId == 4) empresaSapId = "ARCAC";
            else if (empresaId == 5) empresaSapId = "ARPEN";

            // el codigo: "N/A" y la descripcion "Sin Datos"
            List<ZMM_RESPUESTA_CLAS_PROD> respuestaProdList = new List<ZMM_RESPUESTA_CLAS_PROD>();
            List<ZMM_ERROR_CLAS_PROD> erroresProdList = new List<ZMM_ERROR_CLAS_PROD>();
            List<string> codigosProducto = productos.Select(p => p.ProductoIdExterno + p.ColorIdExterno).ToList();
            ObtenerProductoDesdeSAP(codigosProducto, empresaSapId.ToString(), respuestaProdList, erroresProdList);

            // Luego lo actualizo en la base de datos
            ActualizarBaseDeDatosConProductos(serviceOptions, empresaId, productos, respuestaProdList, erroresProdList);

            return productos;
        }

        private void ActualizarBaseDeDatosConProductos(ServiceOptions serviceOptions, int empresaId, List<Producto> productos, List<ZMM_RESPUESTA_CLAS_PROD> respuestaProdList, List<ZMM_ERROR_CLAS_PROD> erroresProdList)
        {
            int i = 0;
            int jproducto = 0;
            StringBuilder errorMsg = new StringBuilder();
            for (i = 0; i < erroresProdList.Count; i++)
            {
                errorMsg.Clear();
                Producto producto = productos[i];
                ZMM_ERROR_CLAS_PROD errorProd = erroresProdList[i];
                ZMM_RESPUESTA_CLAS_PROD respuestaProd = null;

                if (errorProd.MENSAJE == "OK")
                {
                    respuestaProd = respuestaProdList[jproducto];
                    jproducto++;
                }               
           
                try
                {
                    using (TransactionScope tScope = CreateTransactionScope())
                    {
                        using (PlanProdEntities ctx = new PlanProdEntities())
                        {
                            DbProducto dbProducto = null;
                            bool productoNuevo = false;
                            bool problemaDeDatos = false;
                            if (errorProd.MENSAJE == "OK")
                            {
                                // Actualizo el producto
                                if ((producto.ProductoIdExterno + producto.ColorIdExterno) == respuestaProd.PRODUCTO)
                                {
                                    bool productoModificado = false;
                                    dbProducto = ctx.DbProductoes.Where(p => p.ProductoIdExterno == producto.ProductoIdExterno && p.ColorIdExterno == producto.ColorIdExterno).SingleOrDefault();
                                    if (dbProducto == null)
                                    {
                                        problemaDeDatos = false;
                                        productoNuevo = true;
                                        dbProducto = new DbProducto();
                                        dbProducto.AuditUserNameCreacion = serviceOptions.UserName;
                                        dbProducto.AuditFechaCreacion = DateTime.Now;
                                        dbProducto.EmpresaId = empresaId;
                                        dbProducto.ProductoIdExterno = producto.ProductoIdExterno;
                                        //dbProducto.ColorIdExterno = producto.ColorIdExterno;
                                        var dbTemporada = ctx.DbTemporadas.Where(t => t.Activa && t.CodigoExterno == respuestaProd.TEMPORADA).SingleOrDefault();
                                        if (dbTemporada != null)
                                        {
                                            dbProducto.TemporadaId = dbTemporada.Id;
                                        }
                                        else
                                        {
                                            problemaDeDatos = true;
                                            errorMsg.AppendFormat("La temporada (sap:{0}) no se pudo obtener.", respuestaProd.TEMPORADA);
                                        }                                        
                                    }

                                    if (dbProducto.ProductoNombre != respuestaProd.NOMBRE)
                                    {
                                        dbProducto.ProductoNombre = respuestaProd.NOMBRE;
                                    }
                                    
                                    if (dbProducto.ProductoNombre == null)
                                    {
                                        dbProducto.ProductoNombre = string.Empty;
                                    }

                                    // Actualizo las entidades relacionadas
                                    // Color
                                    productoModificado = SincronizacionProductoActualizarColor(empresaId, producto, respuestaProd, ctx, productoModificado, dbProducto);
                                    // Marca
                                    productoModificado = SincronizacionProductoActualizarMarca(empresaId, producto, respuestaProd, ctx, productoModificado, dbProducto);
                                    //Grupo talle
                                    productoModificado = SincronizacionProductoActualizarGrupoTalle(empresaId, producto, respuestaProd, ctx, productoModificado, dbProducto);
                                    // Origen
                                    productoModificado = SincronizacionProductoActualizarOrigen(empresaId, producto, respuestaProd, ctx, productoModificado, dbProducto);
                                    // Linea
                                    productoModificado = SincronizacionProductoActualizarLinea(empresaId, producto, respuestaProd, ctx, productoModificado, dbProducto);
                                    // Categoria
                                    productoModificado = SincronizacionProductoActualizarCategoria(empresaId, producto, respuestaProd, ctx, productoModificado, dbProducto);
                                    // SubCategoria
                                    productoModificado = SincronizacionProductoActualizarSubCategoria(empresaId, producto, respuestaProd, ctx, productoModificado, dbProducto);
                                    // Rubro
                                    productoModificado = SincronizacionProductoActualizarRubro(empresaId, producto, respuestaProd, ctx, productoModificado, dbProducto);
                                    // Calidad
                                    productoModificado = SincronizacionProductoActualizarCalidad(empresaId, producto, respuestaProd, ctx, productoModificado, dbProducto);                                     

                                    // Actualizo el producto en si mismo
                                    if (dbProducto.CodigoOrly != respuestaProd.CODIGOORLY)
                                    {
                                        dbProducto.CodigoOrly = respuestaProd.CODIGOORLY;
                                        productoModificado = true;
                                    }

                                    if (!problemaDeDatos && productoNuevo)
                                    {
                                        ctx.DbProductoes.AddObject(dbProducto);
                                        ctx.SaveChanges();
                                    }
                                 
                                    // Ver de actualizar segunda
                                    if ((dbProducto.ProductoSegundaIdExterno + dbProducto.ColorIdExterno) != respuestaProd.PRODUCTOSEGUNDA && !String.IsNullOrEmpty(respuestaProd.PRODUCTOSEGUNDA))
                                    {
                                        // Obtengo el producto de segunda y lo actualizo
                                        List<Producto> productosSegundaList = new List<Producto>();
                                        Producto productoSegunda = new Producto();
                                        productoSegunda.ProductoIdExterno = respuestaProd.PRODUCTOSEGUNDA.Substring(0,8);
                                        productoSegunda.ColorIdExterno = respuestaProd.PRODUCTOSEGUNDA.Substring(8,3);
                                        productosSegundaList.Add(productoSegunda);

                                        // Llamo al metodo en forma recursiva....
                                        ActualizarProductos(serviceOptions, productosSegundaList, empresaId);

                                        productoSegunda = productosSegundaList.First();
                                        if(productoSegunda.Id != 0)
                                        {
                                            dbProducto.ProductoSegundaId = productoSegunda.Id;
                                            dbProducto.ProductoSegundaIdExterno = productoSegunda.ProductoIdExterno;
                                            productoModificado = true;
                                        }
                                    }

                                    if (productoModificado)
                                    {
                                        dbProducto.AuditUserNameModificacion = serviceOptions.UserName;
                                        dbProducto.AuditFechaModificacion = DateTime.Now;                                        
                                    }

                                    dbProducto.FechaSincronizacion = DateTime.Now;
                                }
                                else
                                {
                                    errorMsg.AppendFormat("El producto solicitado {0}{1}, no coincide con el devuelto por SAP {2}", producto.ProductoIdExterno, producto.ColorIdExterno, respuestaProd.PRODUCTO);
                                }
                            }
                            else
                            {
                                errorMsg.Append(errorProd.MENSAJE); // Asigno el error de sap                        
                            }


                            ctx.SaveChanges();
                            if (dbProducto != null)
                            {
                                producto.Id = dbProducto.Id;
                            }
                            
                            tScope.Complete();
                            if (errorMsg.Length == 0)
                            {
                                errorMsg.AppendFormat("El producto {0}{1} se sincronizó correctamente", producto.ProductoIdExterno, producto.ColorIdExterno);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    errorMsg.AppendFormat("Excepcion: " + GetExceptionMessage(ex));
                }
                finally
                {
                    producto.ErrorMsg = errorMsg.ToString();
                }
            }
        }

        public string GetExceptionMessage(Exception ex)
        {
            StringBuilder builder = new StringBuilder();

            Exception current = ex;
            while (current != null)
            {
                builder.Append(current.Message);
                current = current.InnerException;
            }

            return builder.ToString();
        }

        private bool SincronizacionProductoActualizarCalidad(int empresaId, Producto producto, ZMM_RESPUESTA_CLAS_PROD respuestaProd, PlanProdEntities ctx, bool productoModificado, DbProducto dbProducto)
        {
            if (dbProducto.CalidadExternaId != respuestaProd.CALIDAD)
            {
                if (respuestaProd.CALIDAD != SapNa)
                {
                    // Si no existe lo creo
                    var dbEntity = ctx.DbCalidad.Where(c => c.CodigoExterno == respuestaProd.CALIDAD).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbCalidad();
                        ctx.DbCalidad.AddObject(dbEntity);
                        dbEntity.EmpresaId = empresaId;
                        dbEntity.CodigoExterno = respuestaProd.CALIDAD;
                        dbEntity.Descripcion = respuestaProd.DESC_CALIDAD;
                        productoModificado = true;
                        ctx.SaveChanges();                        
                    }
                    else if (dbEntity.Descripcion != respuestaProd.DESC_CALIDAD)
                    {
                        productoModificado = true;
                        dbEntity.Descripcion = respuestaProd.DESC_CALIDAD;
                        ctx.SaveChanges();                        
                    }

                    dbProducto.CalidadExternaId = respuestaProd.CALIDAD;
                }
                else
                {
                    // ?
                }
            }

            return productoModificado;
        }

        private bool SincronizacionProductoActualizarRubro(int empresaId, Producto producto, ZMM_RESPUESTA_CLAS_PROD respuestaProd, PlanProdEntities ctx, bool productoModificado, DbProducto dbProducto)
        {
            if (dbProducto.RubroId != respuestaProd.RUBRO)
            {
                if (respuestaProd.RUBRO != SapNa)
                {
                    // Si no existe lo creo
                    var dbEntity = ctx.DbRubroes.Where(c => c.Id == respuestaProd.RUBRO).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbRubro();
                        ctx.DbRubroes.AddObject(dbEntity);
                        dbEntity.EmpresaId = empresaId;
                        dbEntity.Id = respuestaProd.RUBRO;
                        dbEntity.Nombre = respuestaProd.DESC_RUBRO;
                        productoModificado = true;
                        ctx.SaveChanges();                        
                    }
                    else if (dbEntity.Nombre != respuestaProd.DESC_RUBRO)
                    {
                        productoModificado = true;
                        dbEntity.Nombre = respuestaProd.DESC_RUBRO;
                        ctx.SaveChanges();                        
                    }

                    dbProducto.RubroId = respuestaProd.RUBRO;
                }
                else
                {
                    // ?
                    throw new Exception("En SAP no está asignado el Rubro de este producto. Debe asignarlo primero en SAP para poder sincronizarlo en este sistema");
                }
            }

            return productoModificado;
        }

        private bool SincronizacionProductoActualizarSubCategoria(int empresaId, Producto producto, ZMM_RESPUESTA_CLAS_PROD respuestaProd, PlanProdEntities ctx, bool productoModificado, DbProducto dbProducto)
        {
            if (dbProducto.SubFamiliaIdExterno != respuestaProd.SUBCATEGORIA)
            {
                if (respuestaProd.SUBCATEGORIA != SapNa)
                {
                    // Si no existe lo creo
                    var dbEntity = ctx.DbSubCategoria.Where(c => c.CodigoExterno == respuestaProd.SUBCATEGORIA).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbSubCategoria();
                        ctx.DbSubCategoria.AddObject(dbEntity);
                        dbEntity.EmpresaId = empresaId;
                        dbEntity.CodigoExterno = respuestaProd.SUBCATEGORIA;
                        dbEntity.Descripcion = respuestaProd.DESC_SUBCATEGORIA;
                        productoModificado = true;
                        ctx.SaveChanges();
                    }
                    else if (dbEntity.Descripcion != respuestaProd.DESC_SUBCATEGORIA)
                    {
                        productoModificado = true;
                        dbEntity.Descripcion = respuestaProd.DESC_SUBCATEGORIA;
                        ctx.SaveChanges();
                    }

                    dbProducto.SubFamiliaIdExterno = respuestaProd.SUBCATEGORIA;
                }
                else
                {
                    // ?
                }
            }

            return productoModificado;
        }

        private bool SincronizacionProductoActualizarGrupoTalle(int empresaId, Producto producto, ZMM_RESPUESTA_CLAS_PROD respuestaProd, PlanProdEntities ctx, bool productoModificado, DbProducto dbProducto)
        {
            if (dbProducto.GrupoTalleId != respuestaProd.GRUPOTALLE)
            {
                if (respuestaProd.GRUPOTALLE != SapNa)
                {
                    // Si no existe lo creo
                    var dbEntity = ctx.DbGrupoTalle.Where(c => c.CodigoExterno == respuestaProd.GRUPOTALLE).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbGrupoTalle();
                        ctx.DbGrupoTalle.AddObject(dbEntity);
                        dbEntity.EmpresaId = empresaId;
                        dbEntity.CodigoExterno = respuestaProd.GRUPOTALLE;
                        dbEntity.Descripcion = respuestaProd.GRUPOTALLE;
                        productoModificado = true;
                        ctx.SaveChanges();
                    }
                    else if (dbEntity.Descripcion != respuestaProd.GRUPOTALLE)
                    {
                        productoModificado = true;
                        dbEntity.Descripcion = respuestaProd.GRUPOTALLE;
                        ctx.SaveChanges();
                    }

                    dbProducto.GrupoTalleId = respuestaProd.GRUPOTALLE;
                }
                else
                {
                    // ?
                }
            }

            return productoModificado;
        }

        private bool SincronizacionProductoActualizarCategoria(int empresaId, Producto producto, ZMM_RESPUESTA_CLAS_PROD respuestaProd, PlanProdEntities ctx, bool productoModificado, DbProducto dbProducto)
        {
            if (dbProducto.FamiliaIdExterno != respuestaProd.CATEGORIA)
            {
                if (respuestaProd.CATEGORIA != SapNa)
                {
                    // Si no existe lo creo
                    var dbEntity = ctx.DbCategoria.Where(c => c.CodigoExterno == respuestaProd.CATEGORIA).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbCategoria();
                        ctx.DbCategoria.AddObject(dbEntity);
                        dbEntity.EmpresaId = empresaId;
                        dbEntity.CodigoExterno = respuestaProd.CATEGORIA;
                        dbEntity.Descripcion = respuestaProd.DESC_CATEGORIA;
                        productoModificado = true;
                        ctx.SaveChanges();
                    }
                    else if (dbEntity.Descripcion != respuestaProd.DESC_CATEGORIA)
                    {
                        productoModificado = true;
                        dbEntity.Descripcion = respuestaProd.DESC_CATEGORIA;
                        ctx.SaveChanges();
                    }

                    dbProducto.FamiliaIdExterno = respuestaProd.CATEGORIA;
                }
                else
                {
                    // ?
                }
            }

            return productoModificado;
        }

        private bool SincronizacionProductoActualizarLinea(int empresaId, Producto producto, ZMM_RESPUESTA_CLAS_PROD respuestaProd, PlanProdEntities ctx, bool productoModificado, DbProducto dbProducto)
        {
            if (dbProducto.LineaIdExterno != respuestaProd.LINEA)
            {
                if (respuestaProd.LINEA != SapNa)
                {
                    // Si no existe lo creo
                    var dbEntity = ctx.DbLinea.Where(c => c.CodigoExterno == respuestaProd.LINEA).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbLinea();
                        ctx.DbLinea.AddObject(dbEntity);
                        dbEntity.EmpresaId = empresaId;
                        dbEntity.CodigoExterno = respuestaProd.LINEA;
                        dbEntity.Descripcion = respuestaProd.DESC_LINEA;
                        productoModificado = true;
                        ctx.SaveChanges();
                    }
                    else if (dbEntity.Descripcion != respuestaProd.DESC_LINEA)
                    {
                        productoModificado = true;
                        dbEntity.Descripcion = respuestaProd.DESC_LINEA;
                        ctx.SaveChanges();
                    }

                    dbProducto.LineaIdExterno = respuestaProd.LINEA;
                }
                else
                {
                    // ?
                }
            }

            return productoModificado;
        }

        private bool SincronizacionProductoActualizarOrigen(int empresaId, Producto producto, ZMM_RESPUESTA_CLAS_PROD respuestaProd, PlanProdEntities ctx, bool productoModificado, DbProducto dbProducto)
        {
            if (dbProducto.OrigenIdExterno != respuestaProd.ORIGEN)
            {
                if (respuestaProd.ORIGEN != SapNa)
                {
                    // Si no existe lo creo
                    var dbEntity = ctx.DbOrigen.Where(c => c.CodigoExterno == respuestaProd.ORIGEN).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbOrigen();
                        ctx.DbOrigen.AddObject(dbEntity);
                        dbEntity.EmpresaId = empresaId;
                        dbEntity.CodigoExterno = respuestaProd.ORIGEN;
                        dbEntity.Descripcion = respuestaProd.DESC_ORIGEN;
                        productoModificado = true;
                        ctx.SaveChanges();
                    }
                    else if (dbEntity.Descripcion != respuestaProd.DESC_ORIGEN)
                    {
                        productoModificado = true;
                        dbEntity.Descripcion = respuestaProd.DESC_ORIGEN;
                        ctx.SaveChanges();
                    }

                    dbProducto.OrigenIdExterno = respuestaProd.ORIGEN;
                }
                else
                {
                    // ?
                }
            }

            return productoModificado;
        }

        private bool SincronizacionProductoActualizarMarca(int empresaId, Producto producto, ZMM_RESPUESTA_CLAS_PROD respuestaProd, PlanProdEntities ctx, bool productoModificado, DbProducto dbProducto)
        {
            if (dbProducto.MarcaIdExterno != respuestaProd.UNIVERSO)
            {
                if (respuestaProd.UNIVERSO != SapNa)
                {
                    // Si no existe lo creo
                    var dbEntity = ctx.DbMarca.Where(c => c.CodigoExterno == respuestaProd.UNIVERSO).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbMarca();
                        ctx.DbMarca.AddObject(dbEntity);
                        dbEntity.EmpresaId = empresaId;
                        dbEntity.CodigoExterno = respuestaProd.UNIVERSO;
                        dbEntity.Descripcion = respuestaProd.DESC_UNIVERSO;
                        productoModificado = true;
                        ctx.SaveChanges();
                    }
                    else if (dbEntity.Descripcion != respuestaProd.DESC_UNIVERSO)
                    {
                        productoModificado = true;
                        dbEntity.Descripcion = respuestaProd.DESC_UNIVERSO;
                        ctx.SaveChanges();
                    }

                    dbProducto.MarcaIdExterno = respuestaProd.UNIVERSO;
                }
                else
                {
                    // ?
                }
            }

            return productoModificado;
        }

        private static bool SincronizacionProductoActualizarColor(int empresaId, Producto producto, ZMM_RESPUESTA_CLAS_PROD respuestaProd, PlanProdEntities ctx, bool productoModificado, DbProducto dbProducto)
        {
            if (dbProducto.ColorIdExterno != producto.ColorIdExterno)
            {
                if (respuestaProd.COLOR != SapNa)
                {
                    // Si no existe lo creo
                    var dbEntity = ctx.DbColor.Where(c => c.CodigoExterno == producto.ColorIdExterno).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbColor();
                        ctx.DbColor.AddObject(dbEntity);
                        dbEntity.EmpresaId = empresaId;
                        dbEntity.CodigoExterno = producto.ColorIdExterno;
                        dbEntity.Descripcion = respuestaProd.COLOR;
                        productoModificado = true;
                        ctx.SaveChanges();
                    }
                    else if (dbEntity.Descripcion != respuestaProd.COLOR)
                    {
                        productoModificado = true;
                        dbEntity.Descripcion = respuestaProd.COLOR;
                        ctx.SaveChanges();
                    }

                    dbProducto.ColorIdExterno = respuestaProd.COLOR;
                }
                else
                {
                    // ?
                }
            }

            return productoModificado;
        }

        private void ObtenerProductoDesdeSAP(List<string> productosCodigo, string empresaId, List<ZMM_RESPUESTA_CLAS_PROD> respuestaProd, List<ZMM_ERROR_CLAS_PROD> erroresProd)
        {
            ZMM_WS_CLASIFICACION_PRODUCTOClient wcfClient = new ZMM_WS_CLASIFICACION_PRODUCTOClient();

            wcfClient.ClientCredentials.UserName.UserName = "gaci";
            wcfClient.ClientCredentials.UserName.Password = "gacivesuvio";

            // Empresa
            //-	1 = Lacoste
            //-	2 = Paula
            //-	5 = Penguin
            //-	4 = Cacharel

            //string empresa = "1";
            //string producto = "0XPH8913QG5";
            //string empresa = "1";
            //string producto = "0XPH8901Q56";

            int size = productosCodigo.Count;

            ZMM_ERROR_CLAS_PROD[] zmmError = new ZMM_ERROR_CLAS_PROD[size];
            ZMM_RESPUESTA_CLAS_PROD[] zmmRespuesta = new ZMM_RESPUESTA_CLAS_PROD[size];
            ZMM_PRODUCTO[] zmmProductos = new ZMM_PRODUCTO[size];

            for (int i = 0; i < size; i++)
            {
                string productoCodigo = productosCodigo[i];
                zmmProductos[i] = new ZMM_PRODUCTO();
                zmmProductos[i].EMPRESA = empresaId;
                zmmProductos[i].PRODUCTO = productoCodigo;
            }

            // el codigo: "N/A" y la descripcion "Sin Datos"
            // Los errores OK

            wcfClient.ZMM_WS_CLASIFICACION_PRODUCTO(ref zmmError, ref zmmRespuesta, ref zmmProductos);

            if (zmmRespuesta != null)
            {
                respuestaProd.AddRange(zmmRespuesta.ToList());
            }

            if (zmmError != null)
            {
                erroresProd.AddRange(zmmError.ToList());
            }
        }

        /// <summary>
        /// Devuelve los productos que no existen
        /// </summary>
        /// <param name="productosAValidar"></param>
        /// <returns></returns>
        public List<ProductoValidation> ValidarProductos(List<ProductoValidation> productosAValidar)
        {
            List<ProductoValidation> productosExistentes;
            List<ProductoValidation> productosARetornar = new List<ProductoValidation>();
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbProducto> query = ctx.DbProductoes;

                Expression<Func<DbProducto, bool>> expression = p => false;

                foreach (ProductoValidation productoAValidar in productosAValidar)
                {
                    if (!String.IsNullOrEmpty(productoAValidar.ColorId) && !String.IsNullOrEmpty(productoAValidar.Producto))
                    {
                        expression = expression.Or(p => p.ProductoIdExterno == productoAValidar.Producto && p.ColorIdExterno == productoAValidar.ColorId);
                    }
                }

                query.Where(expression);

                productosExistentes = (from p in query
                                       select new ProductoValidation()
                                       {
                                           Producto = p.ProductoIdExterno,
                                           ColorId = p.ColorIdExterno
                                       }).ToList();

                foreach (ProductoValidation productoAValidar in productosAValidar)
                {
                    if (!String.IsNullOrEmpty(productoAValidar.ColorId) && !String.IsNullOrEmpty(productoAValidar.Producto))
                    {
                        if (!(productosExistentes.Where(p => p.Producto == productoAValidar.Producto && p.ColorId == productoAValidar.ColorId).Count() > 0))
                        {
                            productosARetornar.Add(productoAValidar);
                        }
                    }
                }
            }

            return productosARetornar;
        }

        /// <summary>
        /// Guarda todo o sino devuelve strings con los errores
        /// </summary>
        /// <param name="serviceOptions"></param>
        /// <param name="ingresoDeProducto"></param>
        /// <returns></returns>
        public List<string> GuardarIngresoDeProductosMasivo(ServiceOptions serviceOptions, List<IngresoDeProducto> ingresoDeProducto)
        {
            // cambiar el nombre al metodo x uno save
            List<string> erroersAInformar = new List<string>();
            List<IngresoDeProducto> productosAGuardar = new List<IngresoDeProducto>();
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    // Cacheo los destinos
                    List<DbDestino> dbDestinoList = ctx.DbDestinoes.ToList();
                    // Cacheo las temporadas
                    List<DbTemporada> dbTemproradasList = ctx.DbTemporadas.Where(t => t.Activa).ToList();
                    StringBuilder builder;
                    string separador = string.Empty;
                    bool errorGlobal = false;
                    foreach (IngresoDeProducto ingresoInput in ingresoDeProducto)
                    {
                        // completar las validaciones para guardar los ingresos de productos               
                        bool errorProveedor = false;
                        var dbProveedor = ctx.DbProveedors.Where(p => p.ProveedorIdExterno == ingresoInput.ProveedorIdExterno).SingleOrDefault();
                        if (dbProveedor == null)
                        {
                            errorProveedor = true;
                        }
                        else
                        {
                            ingresoInput.ProveedorId = dbProveedor.Id;
                        }

                        bool errorProducto = false;
                        var dbProductoo = ctx.DbProductoes.Where(p => p.ProductoIdExterno == ingresoInput.ProductoIdExterno && p.ColorIdExterno == ingresoInput.ColorIdExterno).SingleOrDefault();
                        if (dbProductoo == null)
                        {
                            errorProducto = true;
                        }
                        else
                        {
                            ingresoInput.ProductoId = dbProductoo.Id;
                        }

                        bool errorDestino = false;
                        var dbDestino = dbDestinoList.Where(d => d.CodigoExterno == ingresoInput.DestinoCodigoExterno).SingleOrDefault();
                        if (dbDestino == null)
                        {
                            errorDestino = true;
                        }
                        else
                        {
                            ingresoInput.DestinoId = dbDestino.Id;
                        }

                        bool errorEnTemproada = false;
                        var dbTemporada = dbTemproradasList.Where(t => t.CodigoExterno == ingresoInput.TemporadaCodigoExterno).SingleOrDefault();
                        if (dbTemporada == null)
                        {
                            errorEnTemproada = true;
                        }
                        else
                        {
                            ingresoInput.TemporadaId = dbTemporada.Id;
                        }

                        // Error de duplicados
                        bool errorDeIngresoDuplicado = false;
                        errorDeIngresoDuplicado = ctx.DbIngresoDeProductos.Where(ing => ing.EmpresaId == ingresoInput.EmpresaId &&
                                                              ing.DestinoId == ingresoInput.DestinoId &&
                                                              ing.ProveedorId == ingresoInput.ProveedorId &&
                                                              ing.ProductoId == ingresoInput.ProductoId &&
                                                              ing.Cantidad == ingresoInput.Cantidad &&
                                                              ing.RemitoLetra == ingresoInput.RemitoLetra &&
                                                              ing.RemitoSucursal == ingresoInput.RemitoSucursal &&
                                                              ing.RemitoNumero == ingresoInput.RemitoNumero &&
                                                              ing.FechaEntrega == ingresoInput.FechaEntrega &&
                                                              ing.TemporadaId == ingresoInput.TemporadaId).Count() > 0;

                        if (!errorGlobal)
                        {
                            errorGlobal = errorProducto || errorProveedor || errorDestino || errorEnTemproada || errorDeIngresoDuplicado;
                        }

                        builder = new StringBuilder();
                        separador = string.Empty;

                        if (errorProducto)
                        {
                            builder.AppendFormat("Producto {0} {1}", ingresoInput.ProductoIdExterno, ingresoInput.ColorIdExterno);
                            separador = ", ";
                        }
                        if (errorProveedor)
                        {
                            builder.Append(separador);
                            builder.AppendFormat("Proveedor {0}", ingresoInput.ProveedorIdExterno);
                            separador = ", ";
                        }
                        if (errorDestino)
                        {
                            builder.Append(separador);
                            builder.AppendFormat("Destino {0}", ingresoInput.DestinoId);
                        }

                        if (errorEnTemproada)
                        {
                            builder.Append(separador);
                            builder.AppendFormat("Temporada {0}", ingresoInput.TemporadaCodigoExterno);
                        }

                        if (errorDeIngresoDuplicado)
                        {
                            builder.Append(separador);
                            builder.AppendFormat("El ingreso está duplicado. Producto {0}, Destino {1}, Temporada {2}, Proveedor {3}, Cantidad {4}, Remito {5}-{6}-{7}, Fecha: {8:dd/MM/yyyy}",
                                ingresoInput.ProductoNombreExterno, ingresoInput.DestinoCodigoExterno, ingresoInput.TemporadaCodigoExterno, ingresoInput.ProveedorIdExterno, ingresoInput.Cantidad, ingresoInput.RemitoLetra, ingresoInput.RemitoSucursal, ingresoInput.RemitoNumero, ingresoInput.FechaEntrega);
                        }

                        if (errorProducto || errorProveedor || errorDestino || errorEnTemproada || errorDeIngresoDuplicado)
                        {
                            erroersAInformar.Add(builder.ToString());
                        }
                    }

                    if (!errorGlobal)
                    {
                        DateTime fechaCreacion = DateTime.Now;
                        foreach (IngresoDeProducto ingresoInput in ingresoDeProducto)
                        {
                            DbIngresoDeProducto dbIngreso = new DbIngresoDeProducto();
                            dbIngreso.EmpresaId = ingresoInput.EmpresaId;
                            dbIngreso.DestinoId = ingresoInput.DestinoId;
                            dbIngreso.ProveedorId = ingresoInput.ProveedorId;
                            dbIngreso.ProductoId = ingresoInput.ProductoId;
                            dbIngreso.Cantidad = ingresoInput.Cantidad;
                            dbIngreso.RemitoLetra = ingresoInput.RemitoLetra;
                            dbIngreso.RemitoSucursal = ingresoInput.RemitoSucursal;
                            dbIngreso.RemitoNumero = ingresoInput.RemitoNumero;
                            dbIngreso.FechaEntrega = ingresoInput.FechaEntrega;
                            dbIngreso.TemporadaId = ingresoInput.TemporadaId;
                            dbIngreso.AuditFechaCreacion = fechaCreacion;
                            dbIngreso.AuditUserNameCreacion = serviceOptions.UserName;

                            ctx.DbIngresoDeProductos.AddObject(dbIngreso);
                        }

                        ctx.SaveChanges();
                    }
                }

                tScope.Complete();
            }

            return erroersAInformar;
        }

        public List<Temporada> GetTemporadas(ServiceOptions serviceOptions, string nombre, int empresaId, DateTime? desde, DateTime? hasta, bool? activa)
        {
            List<Temporada> temporadaList = new List<Temporada>();
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbTemporada> query = ctx.DbTemporadas.FilterLogicalRemoved();
                query = query.Where(t => t.EmpresaId == empresaId);

                if (!String.IsNullOrEmpty(nombre))
                {
                    nombre = nombre.ToLower();
                    query = query.Where(t => t.Nombre.Contains(nombre));
                }

                if (activa.HasValue)
                {
                    query = query.Where(t => t.Activa == activa);
                }

                if (desde.HasValue)
                {
                    query = query.Where(t => t.FechaInicio >= desde.Value);
                }

                if (hasta.HasValue)
                {
                    query = query.Where(t => t.FechaFin < hasta.Value);
                }

                query = query.OrderBy(t => t.Nombre);

                if (serviceOptions != null && serviceOptions.UsePages)
                {
                    query = query.Skip(serviceOptions.GetSkip()).Take(serviceOptions.PageSize);
                }

                foreach (var dbTemporada in query.ToList())
                {
                    Temporada t = new Temporada();
                    EntityMapper.Map(dbTemporada, t);
                    t.FechaDesde = dbTemporada.FechaInicio;
                    t.FechaHasta = dbTemporada.FechaFin;
                    temporadaList.Add(t);
                }
            }

            return temporadaList;
        }

        public Temporada GetTemporadaById(ServiceOptions serviceOptions, int temporadaId)
        {
            Temporada temporada = new Temporada();
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                var dbTemporada = (from t in ctx.DbTemporadas.FilterLogicalRemoved()
                                   where t.Id == temporadaId
                                   select t).Single();


                EntityMapper.Map(dbTemporada, temporada);
                temporada.FechaDesde = dbTemporada.FechaInicio;
                temporada.FechaHasta = dbTemporada.FechaFin;

                // Cargo las temporadas
                var dbTemporadaSemanaMesList = dbTemporada.TemporadaSemanaMes.OrderBy(ts => ts.OrdenSemana).ToList();
                foreach (var dbTemporadaSemana in dbTemporadaSemanaMesList)
                {
                    TemporadaSemanaMes tsm = new TemporadaSemanaMes();
                    EntityMapper.Map(dbTemporadaSemana, tsm);
                    temporada.TemporadaSemanaMesList.Add(tsm);
                }
            }

            return temporada;
        }

        public void EliminarTemporada(ServiceOptions serviceOptions, int temporadaId)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    var temporada = ctx.DbTemporadas.Where(t => t.Id == temporadaId).Single();

                    var meses = temporada.TemporadaSemanaMes.ToList();
                    foreach (var detalle in meses)
                    {
                        ctx.DbTemporadaSemanaMes.DeleteObject(detalle);
                    }

                    temporada.TemporadaSemanaMes.Clear();
                    ctx.DbTemporadas.DeleteObject(temporada);
                    ctx.SaveChanges();
                }

                tScope.Complete();
            }
        }

        public Temporada SaveTemporada(ServiceOptions serviceOptions, Temporada temporada)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    DbTemporada dbTemporada;

                    dbTemporada = ctx.DbTemporadas.Where(t => t.Id == temporada.Id).SingleOrDefault();
                    if (dbTemporada == null)
                    {
                        dbTemporada = new DbTemporada();
                        ctx.DbTemporadas.AddObject(dbTemporada);
                        dbTemporada.AuditUserNameCreacion = serviceOptions.UserName;
                        dbTemporada.AuditFechaCreacion = DateTime.Now;
                    }
                    else
                    {
                        dbTemporada.AuditUserNameModificacion = serviceOptions.UserName;
                        dbTemporada.AuditFechaModificacion = DateTime.Now;
                    }

                    if (temporada.FechaDesde > temporada.FechaHasta)
                        throw new Exception("La fecha desde debe ser menor a la fecha hasta");

                    dbTemporada.Activa = temporada.Activa;
                    dbTemporada.EmpresaId = temporada.EmpresaId;
                    dbTemporada.Nombre = temporada.Nombre;
                    dbTemporada.FechaInicio = temporada.FechaDesde;
                    dbTemporada.CodigoExterno = temporada.CodigoExterno;
                    dbTemporada.FechaFin = temporada.FechaHasta;
                    temporada.NumeroSemanas = temporada.NumeroSemanas;
                    dbTemporada.NumeroSemanas = temporada.NumeroSemanas;
                    dbTemporada.LetraTemporada = temporada.LetraTemporada;
                    dbTemporada.MapeoTemporadaExterno = temporada.MapeoTemporadaExterno;

                    // Guardo el detalle

                    // Hay un conjunto que esta en la base que tiene que ser borrado porque no lo envían desde el cliente
                    var listaDeDetallesId = temporada.TemporadaSemanaMesList.Select(ts => ts.Id).ToList();
                    var lstdbDetallleABorrar = dbTemporada.TemporadaSemanaMes.Where(ts => !listaDeDetallesId.Contains(ts.Id)).ToList();
                    lstdbDetallleABorrar.ForEach(o => ctx.DbTemporadaSemanaMes.DeleteObject(o));
                    ctx.SaveChanges();

                    // Cargo o actualizo el nuevo conjunto
                    foreach (var tsm in temporada.TemporadaSemanaMesList)
                    {
                        DbTemporadaSemanaMes dbTsm = null;
                        if (tsm.Id != 0)
                        {
                            dbTsm = dbTemporada.TemporadaSemanaMes.Where(ts => ts.Id == tsm.Id).SingleOrDefault();
                        }

                        if (dbTsm == null)
                        {
                            dbTsm = new DbTemporadaSemanaMes();
                            dbTemporada.TemporadaSemanaMes.Add(dbTsm);
                        }

                        dbTsm.Desde = tsm.Desde;
                        dbTsm.Hasta = tsm.Hasta;
                        dbTsm.NumeroSemana = tsm.NumeroSemana;
                        dbTsm.OrdenSemana = tsm.OrdenSemana;
                        dbTsm.Anio = tsm.Anio;
                        dbTsm.Mes = tsm.Mes;                        
                    }

                    ctx.SaveChanges();
                    temporada.Id = dbTemporada.Id;
                }

                tScope.Complete();               
            }

            return GetTemporadaById(serviceOptions, temporada.Id);
        }

        public List<IngresoDeProducto> GetIngresoDeProducto(ServiceOptions serviceOptions, SearchIngresoDeProducto search)
        {
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbIngresoDeProducto> query = ctx.DbIngresoDeProductos.FilterLogicalRemoved();

                if (!String.IsNullOrEmpty(search.CodigoProducto))
                {
                    query = query.Where(t => t.Producto.ProductoIdExterno.StartsWith(search.CodigoProducto));
                }

                if (!String.IsNullOrEmpty(search.CodigoColor))
                {
                    query = query.Where(t => t.Producto.ColorIdExterno.StartsWith(search.CodigoColor));
                }

                if (search.ProveedorId.HasValue)
                {
                    query = query.Where(t => t.ProveedorId == search.ProveedorId.Value);
                }

                if (search.DestinoId.HasValue)
                {
                    query = query.Where(t => t.DestinoId == search.DestinoId.Value);
                }

                if (search.FechaDesde.HasValue)
                {
                    query = query.Where(t => t.FechaEntrega >= search.FechaDesde.Value);
                }

                if (search.FechaHasta.HasValue)
                {
                    query = query.Where(t => t.FechaEntrega < search.FechaHasta.Value);
                }

                if (search.TemporadaId.HasValue)
                {
                    query = query.Where(t => t.TemporadaId == search.TemporadaId.Value);
                }

                if (!String.IsNullOrEmpty(search.NumeroRemito))
                {
                    query = query.Where(t => t.RemitoNumero == search.NumeroRemito);
                }

                query = query.OrderBy(t => t.FechaEntrega);

                if (serviceOptions != null && serviceOptions.UsePages)
                {
                    query = query.Skip(serviceOptions.GetSkip()).Take(serviceOptions.PageSize);
                }

                if (!serviceOptions.IsAdmin)
                {
                    query = query.Where(d => serviceOptions.Operations.Contains(d.Destino.SecurityKey));
                }

                return (from t in query
                        select new IngresoDeProducto()
                        {
                            Id = t.Id,
                            ProveedorId = t.ProveedorId,
                            ProductoId = t.ProductoId,
                            FechaEntrega = t.FechaEntrega,
                            Cantidad = t.Cantidad,
                            ProductoIdExterno = t.Producto.ProductoIdExterno,
                            DestinoId = t.DestinoId,
                            DestinoCodigoExterno = t.Destino.CodigoExterno,
                            ColorIdExterno = t.Producto.ColorIdExterno,
                            ProductoNombreExterno = t.Producto.ProductoNombre,
                            ProductoColorExterno = t.Producto.Color.Descripcion,
                            ProveedorNombre = t.Proveedor.RazonSocial,
                            EmpresaId = t.EmpresaId,
                            RemitoLetra = t.RemitoLetra,
                            RemitoSucursal = t.RemitoSucursal,
                            RemitoNumero = t.RemitoNumero,
                            TemporadaId = t.TemporadaId,
                            TemporadaCodigoExterno = t.Temporada.CodigoExterno,
                            AuditFechaCreacion = t.AuditFechaCreacion,
                            AuditFechaModificacion = t.AuditFechaModificacion,
                            AuditUserNameCreacion = t.AuditUserNameCreacion,
                            AuditUserNameModificacion = t.AuditUserNameModificacion,
                            Removed = t.Removed
                        }).ToList();
            }
        }

        public IngresoDeProducto GetIngresoDeProductoById(ServiceOptions serviceOptions, int ingresoProductoId)
        {
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                return (from t in ctx.DbIngresoDeProductos
                        where t.Id == ingresoProductoId
                        select new IngresoDeProducto()
                        {
                            Id = t.Id,
                            ProveedorId = t.ProveedorId,
                            ProductoId = t.ProductoId,
                            FechaEntrega = t.FechaEntrega,
                            Cantidad = t.Cantidad,
                            ProductoIdExterno = t.Producto.ProductoIdExterno,
                            DestinoId = t.DestinoId,
                            DestinoCodigoExterno = t.Destino.CodigoExterno,
                            ColorIdExterno = t.Producto.ColorIdExterno,
                            ProductoNombreExterno = t.Producto.ProductoNombre,
                            ProductoColorExterno = t.Producto.Color.Descripcion,
                            ProveedorNombre = t.Proveedor.RazonSocial,
                            EmpresaId = t.EmpresaId,
                            RemitoLetra = t.RemitoLetra,
                            RemitoSucursal = t.RemitoSucursal,
                            RemitoNumero = t.RemitoNumero,
                            TemporadaId = t.TemporadaId,
                            TemporadaCodigoExterno = t.Temporada.CodigoExterno,
                            AuditFechaCreacion = t.AuditFechaCreacion,
                            AuditFechaModificacion = t.AuditFechaModificacion,
                            AuditUserNameCreacion = t.AuditUserNameCreacion,
                            AuditUserNameModificacion = t.AuditUserNameModificacion,
                            Removed = t.Removed
                        }).Single();
            }
        }

        public void EliminarIngresoDeProducto(ServiceOptions serviceOptions, int ingresoProductoId)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    var ingreso = ctx.DbIngresoDeProductos.Where(t => t.Id == ingresoProductoId).Single();
                    ctx.DbIngresoDeProductos.DeleteObject(ingreso);
                    ctx.SaveChanges();
                }

                tScope.Complete();
            }
        }

        public IngresoDeProducto SaveIngresoDeProducto(ServiceOptions serviceOptions, IngresoDeProducto ingresoDeProducto)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    DbIngresoDeProducto dbIngersoDeProducto;

                    dbIngersoDeProducto = ctx.DbIngresoDeProductos.Where(t => t.Id == ingresoDeProducto.Id).SingleOrDefault();
                    if (dbIngersoDeProducto == null)
                    {
                        dbIngersoDeProducto = new DbIngresoDeProducto();
                        ctx.DbIngresoDeProductos.AddObject(dbIngersoDeProducto);
                        dbIngersoDeProducto.AuditUserNameCreacion = serviceOptions.UserName;
                        dbIngersoDeProducto.AuditFechaCreacion = DateTime.Now;
                        dbIngersoDeProducto.EmpresaId = ingresoDeProducto.EmpresaId;
                    }
                    else
                    {
                        dbIngersoDeProducto.AuditUserNameModificacion = serviceOptions.UserName;
                        dbIngersoDeProducto.AuditFechaModificacion = DateTime.Now;
                    }

                    dbIngersoDeProducto.ProveedorId = ingresoDeProducto.ProveedorId;

                    if (ingresoDeProducto.DestinoId == 0 && !String.IsNullOrEmpty(ingresoDeProducto.DestinoCodigoExterno))
                    {
                        ingresoDeProducto.DestinoId = ctx.DbDestinoes.Where(d => d.CodigoExterno == ingresoDeProducto.DestinoCodigoExterno).Select(d => d.Id).Single();
                    }

                    dbIngersoDeProducto.DestinoId = ingresoDeProducto.DestinoId;

                    if (ingresoDeProducto.TemporadaId == 0 && !String.IsNullOrEmpty(ingresoDeProducto.TemporadaCodigoExterno))
                    {
                        ingresoDeProducto.TemporadaId = ctx.DbTemporadas.Where(t => t.CodigoExterno == ingresoDeProducto.TemporadaCodigoExterno).Select(t => t.Id).Single();
                    }

                    dbIngersoDeProducto.TemporadaId = ingresoDeProducto.TemporadaId;

                    dbIngersoDeProducto.ProductoId = ingresoDeProducto.ProductoId;
                    dbIngersoDeProducto.FechaEntrega = ingresoDeProducto.FechaEntrega;
                    dbIngersoDeProducto.Cantidad = ingresoDeProducto.Cantidad;
                    dbIngersoDeProducto.RemitoLetra = ingresoDeProducto.RemitoLetra;
                    dbIngersoDeProducto.RemitoSucursal = ingresoDeProducto.RemitoSucursal;
                    dbIngersoDeProducto.RemitoNumero = ingresoDeProducto.RemitoNumero;

                    ctx.SaveChanges();
                    ingresoDeProducto.Id = dbIngersoDeProducto.Id;
                }

                tScope.Complete();

                return ingresoDeProducto;
            }
        }

        public List<CausaDesvio> GetCausasDesvios(ServiceOptions serviceOptions, int empresaId, string nombreLike)
        {
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbDesvioCausa> query = ctx.DbDesvioCausas.Where(d => d.EmpresaId == empresaId).FilterLogicalRemoved();

                if (!String.IsNullOrEmpty(nombreLike))
                {
                    query = query.Where(d => d.Nombre.Contains(nombreLike));
                }

                query = query.OrderBy(c => c.Nombre);

                if (serviceOptions != null && serviceOptions.UsePages)
                {
                    query = query.Skip(serviceOptions.GetSkip()).Take(serviceOptions.PageSize);
                }

                return (from d in query
                        select new CausaDesvio()
                        {
                            Id = d.Id,
                            Nombre = d.Nombre,
                            AuditFechaCreacion = d.AuditFechaCreacion,
                            AuditFechaModificacion = d.AuditFechaModificacion,
                            AuditUserNameCreacion = d.AuditUserNameCreacion,
                            AuditUserNameModificacion = d.AuditUserNameModificacion

                        }).ToList();
            }
        }

        public CausaDesvio GetCausaDeDesvioById(ServiceOptions serviceOptions, int causaDesvioId)
        {
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbDesvioCausa> query = ctx.DbDesvioCausas.Where(d => d.Id == causaDesvioId).FilterLogicalRemoved();

                return (from d in query
                        select new CausaDesvio()
                        {
                            Id = d.Id,
                            Nombre = d.Nombre,
                            EmpresaId = d.EmpresaId,
                            AuditFechaCreacion = d.AuditFechaCreacion,
                            AuditFechaModificacion = d.AuditFechaModificacion,
                            AuditUserNameCreacion = d.AuditUserNameCreacion,
                            AuditUserNameModificacion = d.AuditUserNameModificacion
                        }).Single();
            }
        }

        public CausaDesvio SaveCausaDesvio(ServiceOptions serviceOptions, CausaDesvio causaDesvio)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    DbDesvioCausa dbDesvioCausa;

                    dbDesvioCausa = ctx.DbDesvioCausas.Where(t => t.Id == causaDesvio.Id).SingleOrDefault();
                    if (dbDesvioCausa == null)
                    {
                        dbDesvioCausa = new DbDesvioCausa();
                        ctx.DbDesvioCausas.AddObject(dbDesvioCausa);
                        dbDesvioCausa.AuditFechaCreacion = DateTime.Now;
                        dbDesvioCausa.AuditUserNameCreacion = serviceOptions.UserName;
                    }
                    else
                    {
                        dbDesvioCausa.AuditFechaModificacion = DateTime.Now;
                        dbDesvioCausa.AuditUserNameModificacion = serviceOptions.UserName;
                    }

                    dbDesvioCausa.EmpresaId = causaDesvio.EmpresaId;
                    dbDesvioCausa.Nombre = causaDesvio.Nombre;

                    ctx.SaveChanges();

                    causaDesvio.Id = dbDesvioCausa.Id;

                    tScope.Complete();

                    return causaDesvio;
                }
            }
        }

        public void EliminarDesvioCausa(ServiceOptions serviceOptions, int causaDesvioId)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    var desvioCausa = ctx.DbDesvioCausas.Where(t => t.Id == causaDesvioId).Single();
                    ctx.DbDesvioCausas.DeleteObject(desvioCausa);
                    ctx.SaveChanges();
                }

                tScope.Complete();
            }
        }

        public Desvio GetDesvioById(ServiceOptions serviceOptions, int desvioId)
        {
            Desvio desvio;

            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                DbPlanProdDesvio dbDesvio = ctx.DbPlanProdDesvios.Where(d => d.Id == desvioId).FilterLogicalRemoved().Single();

                desvio = GetDesvioFromDbDesvio(dbDesvio);
            }

            return desvio;
        }

        private Desvio GetDesvioFromDbDesvio(DbPlanProdDesvio dbDesvio)
        {
            Desvio desvio = new Desvio();

            desvio.Id = dbDesvio.Id;
            desvio.PlanProduccionDetallePrimeraId = dbDesvio.PlanProduccionDetalleId;
            desvio.PlanProduccionDetalleSegundaId = dbDesvio.PlanProduccionDetalleSegundaId;
            desvio.Estado = dbDesvio.Estado;
            desvio.UsuarioAprobador = dbDesvio.UsuarioAprobacion;
            desvio.FechaAprobacion = dbDesvio.FechaAprobacion;
            desvio.CausaDesvioId = dbDesvio.DesvioCausaId;
            desvio.CausaDesvioNombre = dbDesvio.DesvioCausa.Nombre;
            desvio.UsuarioCreador = dbDesvio.UsuarioCreacion;
            desvio.FechaCreacion = dbDesvio.FechaCreacion;
            desvio.ProductoId = dbDesvio.PlanProduccionDetalle.ProductoId;
            desvio.ProductoSapArticuloNombre = dbDesvio.PlanProduccionDetalle.Producto.ProductoNombre;
            desvio.ProductoIdExterno = dbDesvio.PlanProduccionDetalle.Producto.ProductoIdExterno;
            desvio.FechaDeDesvio = dbDesvio.FechaDesvio;
            desvio.ProductoSapColorNombre = dbDesvio.PlanProduccionDetalle.Producto.Color.Descripcion;
            desvio.PlanProduccionId = dbDesvio.PlanProduccionDetalle.PlanProduccion.Id;

            desvio.AuditFechaCreacion = dbDesvio.AuditFechaCreacion;
            desvio.AuditFechaModificacion = dbDesvio.AuditFechaModificacion;
            desvio.AuditUserNameCreacion = dbDesvio.AuditUserNameCreacion;
            desvio.AuditUserNameModificacion = dbDesvio.AuditUserNameModificacion;

            foreach (DbPlanProdDesvioDetalle dbDesvioDetalle in dbDesvio.PlanProdDesvioDetalles)
            {
                DesvioDetalle desvioDetalle = new DesvioDetalle();
                desvioDetalle.DesvioId = desvio.Id;
                desvioDetalle.Id = dbDesvioDetalle.Id;
                desvioDetalle.DetalleProductoCantidadId = dbDesvioDetalle.DetalleCantidadesId;
                desvioDetalle.CantidadInicial = dbDesvioDetalle.CantidadOriginal;
                desvioDetalle.CantidadFinal = dbDesvioDetalle.CantidadFinal;
                desvioDetalle.NumeroSemana = dbDesvioDetalle.PlanProduccionDetalleCantidade.NumeroSemana;

                desvioDetalle.AuditFechaCreacion = dbDesvioDetalle.AuditFechaCreacion;
                desvioDetalle.AuditFechaModificacion = dbDesvioDetalle.AuditFechaModificacion;
                desvioDetalle.AuditUserNameCreacion = dbDesvioDetalle.AuditUserNameCreacion;
                desvioDetalle.AuditUserNameModificacion = dbDesvioDetalle.AuditUserNameModificacion;

                desvio.DesvioDetalles.Add(desvioDetalle);
            }

            return desvio;
        }

        public Desvio GetDesvioByProductoDelPlanDeProduccion(ServiceOptions serviceOptions, int detalleProductoId)
        {
            Desvio desvio = null;
            string estadoAprobadoEnProgreso = Convert.ToString((char)EstadoCharAprobado.EnProgreso);
            string estadoAprobadoEsperandoAprobacion = Convert.ToString((char)EstadoCharAprobado.EsperandoAprobacion);

            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    DbPlanProdDesvio dbDesvio = ctx.DbPlanProdDesvios.Where(d => d.PlanProduccionDetalleId == detalleProductoId && (d.Estado == estadoAprobadoEnProgreso || d.Estado == estadoAprobadoEsperandoAprobacion)).FilterLogicalRemoved().SingleOrDefault();

                    var producto = (from prod in ctx.DbProductoes.FilterLogicalRemoved()
                                    join detalle in ctx.DbPlanProduccionDetalles on prod.Id equals detalle.ProductoId
                                    where detalle.Id == detalleProductoId
                                    select prod).Single();

                    bool esProductoDePrimera = producto.CalidadExternaId == "1";

                    if (dbDesvio == null)
                    {
                        // Se puede dar que el parametro sea de un desvio para un producto de segunda
                        dbDesvio = ctx.DbPlanProdDesvios.Where(d => d.PlanProduccionDetalleSegundaId.HasValue && d.PlanProduccionDetalleSegundaId.Value == detalleProductoId && (d.Estado == estadoAprobadoEnProgreso || d.Estado == estadoAprobadoEsperandoAprobacion)).SingleOrDefault();
                    }

                    if (dbDesvio != null)
                    {
                        desvio = GetDesvioFromDbDesvio(dbDesvio);
                    }
                    else
                    {
                        // No existe desvio para primera ni para segunda.

                        // Hack, tengo que obtener correctamente el parametro de si el detalle de producto es para un producto de primera o segunda
                        // y devolverselo a la UI, se lo devuelvo en el objeto desvio, aunque este no represente nada. Es la relación entre
                        // los productos lo que devuelvo
                        // La otra opcion es grabar un desvio aqui
                        desvio = new Desvio();
                        desvio.Estado = Convert.ToString((char)EstadoCharAprobado.EnProgreso);

                        DbPlanProduccionDetalle dbPlanProduccionDetalle = ctx.DbPlanProduccionDetalles.Where(d => d.Id == detalleProductoId).Single();

                        int detalleProductoPrimeraId = 0;
                        int? detalleProductoSegundaId = null;
                        DbPlanProduccionDetalle dbPlanProduccionDetalleSegunda = null;

                        if (esProductoDePrimera)
                        {
                            detalleProductoPrimeraId = dbPlanProduccionDetalle.Id;

                            // El producto del detalle tiene segunda?
                            if (dbPlanProduccionDetalle.Producto.ProductoSegundaId.HasValue)
                            {
                                // Obtengo el detalle de segunda si existe
                                dbPlanProduccionDetalleSegunda = ctx.DbPlanProduccionDetalles.Where(d => d.PlanProduccionId == dbPlanProduccionDetalle.PlanProduccionId && d.ProductoId == dbPlanProduccionDetalle.Producto.ProductoSegundaId.Value).SingleOrDefault();
                                if (dbPlanProduccionDetalleSegunda != null)
                                {
                                    // Hay un detalle con el producto de segunda
                                    detalleProductoSegundaId = dbPlanProduccionDetalleSegunda.Id;
                                }
                                else
                                {
                                    // No hay un detalle pero el producto existe, por lo tanto
                                    // creo el detalle de segunda para el plan de producción
                                    dbPlanProduccionDetalleSegunda = new DbPlanProduccionDetalle();
                                    dbPlanProduccionDetalleSegunda.ProductoId = dbPlanProduccionDetalle.Producto.ProductoSegundaId.Value;
                                    dbPlanProduccionDetalleSegunda.PlanProduccionId = dbPlanProduccionDetalle.PlanProduccionId;
                                    dbPlanProduccionDetalleSegunda.AuditFechaCreacion = DateTime.Now;
                                    dbPlanProduccionDetalleSegunda.AuditUserNameCreacion = serviceOptions.UserName;

                                    ctx.DbPlanProduccionDetalles.AddObject(dbPlanProduccionDetalleSegunda);

                                    int numeroSemanas = dbPlanProduccionDetalle.PlanProduccion.Temporada.NumeroSemanas;

                                    Temporada temporada = this.GetTemporadaById(null, dbPlanProduccionDetalle.PlanProduccion.Temporada.Id);
                                    HybridDictionary hdictonary = temporada.GetHybridOrdenNumeroSemana();

                                    for (int i = 0; i < numeroSemanas; i++)
                                    {
                                        DbPlanProduccionDetalleCantidade dbPlanProduccionDetalleCantidade = new DbPlanProduccionDetalleCantidade();
                                        dbPlanProduccionDetalleCantidade.NumeroSemana = Convert.ToInt32(hdictonary[i]);
                                        dbPlanProduccionDetalleCantidade.Cantidad = 0;
                                        dbPlanProduccionDetalleSegunda.PlanProduccionDetalleCantidades.Add(dbPlanProduccionDetalleCantidade);
                                        dbPlanProduccionDetalleCantidade.AuditFechaCreacion = DateTime.Now;
                                        dbPlanProduccionDetalleCantidade.AuditUserNameCreacion = serviceOptions.UserName;
                                    }

                                    ctx.SaveChanges();
                                    detalleProductoSegundaId = dbPlanProduccionDetalleSegunda.Id;
                                }
                            }
                        }
                        else
                        {
                            // El producto del detalle no tiene segunda, o no se cargó todavía la segunda o él mismo es de segunda

                            //// Me fijo que ningún producto lo tenga a él de segunda
                            //DbProducto productoQueTieneParamDeSegunda = ctx.DbProductoes.Where(p => p.ProductoSegundaId.HasValue && p.ProductoSegundaId.Value == dbPlanProduccionDetalle.Producto.Id).SingleOrDefault();

                            //// No hay productos que lo tengan a él mismo de segunda
                            //if (productoQueTieneParamDeSegunda == null)
                            //{
                            //    detalleProductoPrimeraId = detalleProductoId;
                            //    detalleProductoSegundaId = null;
                            //}
                            //else
                            //{
                            //    // El producto es de segunda y no tiene cargada la primera?
                            //    throw new Exception("Todavia no se pueden cargar productos solo de segunda");
                            //    // Hay un producto que lo tiene de segunda, entonces el parámetro es de segunda y el que encontré es el de primera
                            //    //detalleProductoPrimeraId = ctx.DbPlanProduccionDetalles.Where(d => d.ProductoId == productoQueTieneParamDeSegunda.Id && d.PlanProduccionId == dbPlanProduccionDetalle.PlanProduccionId).Single().Id;
                            //    //detalleProductoSegundaId = dbPlanProduccionDetalle.Id;
                            //}


                            // El producto del detalle es de segunda

                            // si es de segunda, solo se levanta el de segunda, pero lo mando como primera, sin segunda. Ya que carga como si fuese uno de primera
                            detalleProductoPrimeraId = detalleProductoId;
                            detalleProductoSegundaId = null;
                        }

                        desvio.PlanProduccionDetallePrimeraId = detalleProductoPrimeraId;
                        desvio.PlanProduccionDetalleSegundaId = detalleProductoSegundaId;
                    }
                }

                tScope.Complete();
            }

            return desvio;
        }

        public void IncorporarDesvios(ServiceOptions serviceOptions, int planProduccionId, int tipoDesvioId, int causaDesvioId, List<DesvioUpdate> desviosUpdate)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    IncorporarDesviosInternal(ctx, serviceOptions, planProduccionId, tipoDesvioId, causaDesvioId, desviosUpdate, null);

                    tScope.Complete();
                }
            }
        }

        /// <summary>
        /// Metodo similar a void IncorporarDesvios(ServiceOptions serviceOptions, int planProduccionId, int tipoDesvioId, int causaDesvioId, List<DesvioUpdate> desviosUpdate)
        /// pero si tener una transacción y recibiendo el contexto de parámetro
        /// </summary>
        /// <param name="serviceOptions"></param>
        /// <param name="planProduccionId"></param>
        /// <param name="tipoDesvioId"></param>
        /// <param name="causaDesvioId"></param>
        /// <param name="desviosUpdate"></param>
        /// <param name="tipoDesvio"></param>
        /// <param name="ctx"></param>
        internal IncorporarDesvioResult IncorporarDesviosInternal(PlanProdEntities ctx, ServiceOptions serviceOptions, int planProduccionId, int tipoDesvioId, int causaDesvioId, List<DesvioUpdate> desviosUpdate, SanJuanRegistroDeDesvios registroDeDesvios)
        {
            IncorporarDesvioResult resultado = new IncorporarDesvioResult();
            resultado.IncorporadoOK = false;
            
            // Tengo que validar que no exista el detalle de sap de san juan
            bool procesar = true;
            if (registroDeDesvios != null)
            {
                if (ctx.DbPlanProdDesvioOrigens.Where(o => o.ClaveNatural == registroDeDesvios.ClaveNatural).Count() > 0)
                {
                    resultado.Mensaje = string.Format("Este registro ya fue procesado {0}", registroDeDesvios.ClaveNatural);
                    procesar = false;
                }
            }

            if (procesar)
            {
                TipoDesvio tipoDesvio = (TipoDesvio)tipoDesvioId;
                DbPlanProduccion dbPlanDeProduccion = ctx.DbPlanProduccions.Where(p => p.Id == planProduccionId).Single();

                // Analizo cuales son desvios y en el caso de ser de segunda agrego los productos al plan de produccion
                foreach (DesvioUpdate desvioUpdate in desviosUpdate)
                {
                    DbPlanProduccionDetalle detalleProducto = dbPlanDeProduccion.PlanProduccionDetalles.Where(d => d.ProductoId == desvioUpdate.ProductoId).SingleOrDefault();

                    if (detalleProducto == null)
                    {
                        // Agrego el producto porque seguramente es de segunda
                        detalleProducto = AgregarProductoAlPlan(serviceOptions, planProduccionId, dbPlanDeProduccion, desvioUpdate.ProductoId);
                        ctx.SaveChanges();
                    }

                    bool desvioParaElProducto = false;
                    foreach (var cantidadSemana in detalleProducto.PlanProduccionDetalleCantidades)
                    {
                        // Busco el del desvio
                        var desvioDetalle = desvioUpdate.Detalles.Where(s => s.NumeroSemana == cantidadSemana.NumeroSemana).SingleOrDefault();

                        if (desvioDetalle != null)
                        {
                            if (desvioDetalle.Cantidad != cantidadSemana.Cantidad)
                            {
                                desvioParaElProducto = true;
                                break;
                            }
                        }
                    }

                    desvioUpdate.EsRealmenteDesvio = desvioParaElProducto;

                    // Si es un desvio, analizo si esta el producto de segunda, si no esta lo creo
                    if (desvioParaElProducto && tipoDesvio == TipoDesvio.PasajeASegunda)
                    {
                        if (detalleProducto.Producto.ProductoSegundaId.HasValue)
                        {
                            int detalleProductoSegundaID = detalleProducto.Producto.ProductoSegundaId.Value;
                            DbPlanProduccionDetalle dbPlanProduccionDetalleSegunda = dbPlanDeProduccion.PlanProduccionDetalles.Where(d => d.ProductoId == detalleProductoSegundaID).SingleOrDefault();

                            if (dbPlanProduccionDetalleSegunda == null)
                            {
                                // TODO: Tengo que agregar el detalle del producto de segunda al plan de producción si no está
                                dbPlanProduccionDetalleSegunda = AgregarProductoAlPlan(serviceOptions, planProduccionId, dbPlanDeProduccion, detalleProductoSegundaID);
                            }

                            ctx.SaveChanges();
                        }
                    }
                }

                List<DbPlanProdDesvio> dbDesvios = new List<DbPlanProdDesvio>();
                foreach (DesvioUpdate desvioUpdate in desviosUpdate)
                {
                    if (desvioUpdate.EsRealmenteDesvio)
                    {
                        resultado.IncorporadoOK = true;
                        DbPlanProduccionDetalle detalleProducto = dbPlanDeProduccion.PlanProduccionDetalles.Where(d => d.ProductoId == desvioUpdate.ProductoId).SingleOrDefault();
                        string estadoDesvioStr = Convert.ToString((char)EstadoCharAprobado.EsperandoAprobacion);
                        bool desvioPendienteDeAprobacion = detalleProducto.PlanProdDesvios.Where(d => d.Estado == estadoDesvioStr).Count() > 0;

                        DbPlanProdDesvio dbDesvio = new DbPlanProdDesvio();
                        dbDesvios.Add(dbDesvio);
                        AsignarDetalleADesvio(ctx, dbDesvio, registroDeDesvios);
                        ctx.DbPlanProdDesvios.AddObject(dbDesvio);
                        dbDesvio.AuditFechaCreacion = DateTime.Now;
                        dbDesvio.AuditUserNameCreacion = serviceOptions.UserName;
                        dbDesvio.UsuarioCreacion = serviceOptions.UserName;
                        dbDesvio.FechaCreacion = DateTime.Now;

                        dbDesvio.PlanProduccionDetalleId = detalleProducto.Id;
                        if (tipoDesvio == TipoDesvio.PasajeASegunda)
                        {
                            int detalleProductoSegundaID = detalleProducto.Producto.ProductoSegundaId.Value;
                            DbPlanProduccionDetalle dbPlanProduccionDetalleSegunda = dbPlanDeProduccion.PlanProduccionDetalles.Where(d => d.ProductoId == detalleProductoSegundaID).SingleOrDefault();
                            dbDesvio.PlanProduccionDetalleSegundaId = dbPlanProduccionDetalleSegunda.Id;
                        }

                        dbDesvio.TipoMovimiento = tipoDesvioId;
                        dbDesvio.Estado = Convert.ToString((char)EstadoCharAprobado.Aprobado);
                        dbDesvio.DesvioCausaId = causaDesvioId;

                        // TODO: Desviar el producto de segunda
                        if (tipoDesvio == TipoDesvio.PasajeASegunda)
                        {
                            DbPlanProduccionDetalle detalleProductoSegunda = dbPlanDeProduccion.PlanProduccionDetalles.Where(d => d.Id == dbDesvio.PlanProduccionDetalleSegundaId).SingleOrDefault();
                            // Analizar el producto de segunda
                            foreach (var cantidadSemana in detalleProductoSegunda.PlanProduccionDetalleCantidades)
                            {
                                // Busco el del desvio
                                var desvioDetalle = desvioUpdate.Detalles.Where(s => s.NumeroSemana == cantidadSemana.NumeroSemana).SingleOrDefault();
                                // Para segunda analizo que la cantidad sea distinta de cero porque estoy sumando
                                if (desvioDetalle != null && desvioDetalle.Cantidad != 0)
                                {
                                    DbPlanProdDesvioDetalle dbDetalleDeDesvio = new DbPlanProdDesvioDetalle();
                                    dbDesvio.PlanProdDesvioDetalles.Add(dbDetalleDeDesvio);
                                    dbDetalleDeDesvio.AuditFechaCreacion = DateTime.Now;
                                    dbDetalleDeDesvio.AuditUserNameCreacion = serviceOptions.UserName;
                                    dbDetalleDeDesvio.DetalleCantidadesId = cantidadSemana.Id;
                                    dbDetalleDeDesvio.CantidadOriginal = cantidadSemana.Cantidad;
                                    dbDetalleDeDesvio.CantidadFinal = cantidadSemana.Cantidad + desvioDetalle.Cantidad; // Es una suma a segunda
                                }
                            }
                        }

                        // Analizar el producto de primera
                        foreach (var cantidadSemana in detalleProducto.PlanProduccionDetalleCantidades)
                        {
                            // Busco el del desvio
                            var desvioDetalle = desvioUpdate.Detalles.Where(s => s.NumeroSemana == cantidadSemana.NumeroSemana).SingleOrDefault();
                            if (desvioDetalle != null && (desvioDetalle.Cantidad != cantidadSemana.Cantidad))
                            {
                                DbPlanProdDesvioDetalle dbDetalleDeDesvio = new DbPlanProdDesvioDetalle();
                                dbDesvio.PlanProdDesvioDetalles.Add(dbDetalleDeDesvio);
                                dbDetalleDeDesvio.AuditFechaCreacion = DateTime.Now;
                                dbDetalleDeDesvio.AuditUserNameCreacion = serviceOptions.UserName;
                                dbDetalleDeDesvio.DetalleCantidadesId = cantidadSemana.Id;
                                dbDetalleDeDesvio.CantidadOriginal = cantidadSemana.Cantidad;
                                if (tipoDesvio == TipoDesvio.PasajeASegunda)
                                {
                                    dbDetalleDeDesvio.CantidadFinal = cantidadSemana.Cantidad - desvioDetalle.Cantidad; // se lo resto porque paso a segunda
                                }
                                else
                                {
                                    dbDetalleDeDesvio.CantidadFinal = desvioDetalle.Cantidad;
                                }
                            }
                        }
                    }
                }

                ctx.SaveChanges();

                //Apruebo los desvios
                foreach (var dbDesvio in dbDesvios)
                {
                    LoadDbDesvioParaAprobar(serviceOptions, dbDesvio.Id, serviceOptions.UserName, EstadoCharAprobado.Aprobado, ctx, dbDesvio);
                }

                ctx.SaveChanges();
            }

            return resultado;
        }

        private void AsignarDetalleADesvio(PlanProdEntities ctx, DbPlanProdDesvio dbDesvio, SanJuanRegistroDeDesvios registroDeDesvios)
        {
            if(registroDeDesvios != null)
            {
                DbPlanProdDesvioOrigen dbOrigenDesvio;
                foreach(var detalleSap in registroDeDesvios.DetalleDeSap)
                {                    
                    dbOrigenDesvio = new DbPlanProdDesvioOrigen();
                    dbDesvio.PlanProdDesvioOrigens.Add(dbOrigenDesvio);
                    dbOrigenDesvio.Fecha = DateTime.ParseExact(string.Format("{0} {1}", detalleSap.FECHA, detalleSap.HORA), "yyyy-MM-dd HH:mm:ss", null);
                    dbDesvio.FechaDesvio = dbOrigenDesvio.Fecha;
                    dbOrigenDesvio.Destino = detalleSap.DESTINO;
                    dbOrigenDesvio.Producto = detalleSap.PRODUCTO;
                    dbOrigenDesvio.ProductoSegunda = detalleSap.PRODUCTOSEGUNDA;
                    dbOrigenDesvio.NumeroSemana = registroDeDesvios.NumeroSemana;
                    dbOrigenDesvio.TipoDescripcion = registroDeDesvios.TipoDescripcion;
                    dbOrigenDesvio.Tipo = detalleSap.TIPO;
                    dbOrigenDesvio.Cantidad = detalleSap.CANTIDAD;
                    dbOrigenDesvio.MotivoDesvio = detalleSap.MOTIVODESVIO.ToString();
                    dbOrigenDesvio.ClaveNatural = registroDeDesvios.ClaveNatural;

                    if(detalleSap.FECHANUEVA != "0000-00-00")
                    {
                        dbOrigenDesvio.FechaNueva = DateTime.ParseExact(detalleSap.FECHANUEVA, "yyyy-MM-dd", null);
                    }

                    dbOrigenDesvio.Temporada = detalleSap.TEMPORADA;
                    dbOrigenDesvio.OT = detalleSap.OT;
                    dbOrigenDesvio.Paquete = detalleSap.PAQUETE;
                    dbOrigenDesvio.Cod_Ope_Sap = detalleSap.COD_OPE_SAP;
                    //dbDesvio.PlanProdDesvioOrigens
                }            
            }
        }

        private DbPlanProduccionDetalle AgregarProductoAlPlan(ServiceOptions serviceOptions, int planProduccionId, DbPlanProduccion dbPlanDeProduccion, int detalleProductoSegundaID)
        {
            DbPlanProduccionDetalle dbPlanProduccionDetalleSegunda = new DbPlanProduccionDetalle();
            dbPlanDeProduccion.PlanProduccionDetalles.Add(dbPlanProduccionDetalleSegunda);
            dbPlanProduccionDetalleSegunda.ProductoId = detalleProductoSegundaID;
            dbPlanProduccionDetalleSegunda.PlanProduccionId = planProduccionId;
            dbPlanProduccionDetalleSegunda.AuditFechaCreacion = DateTime.Now;
            dbPlanProduccionDetalleSegunda.AuditUserNameCreacion = serviceOptions.UserName;

            //ctx.DbPlanProduccionDetalles.AddObject(dbPlanProduccionDetalleSegunda);
            Temporada temporada = GetTemporadaById(null, dbPlanDeProduccion.Temporada.Id);
            HybridDictionary hdictionary = temporada.GetHybridOrdenNumeroSemana();

            int numeroSemanas = dbPlanDeProduccion.Temporada.NumeroSemanas;
            for (int i = 0; i < numeroSemanas; i++)
            {
                DbPlanProduccionDetalleCantidade dbPlanProduccionDetalleCantidade = new DbPlanProduccionDetalleCantidade();
                dbPlanProduccionDetalleCantidade.NumeroSemana = Convert.ToInt32(hdictionary[i]);
                dbPlanProduccionDetalleCantidade.Cantidad = 0;
                dbPlanProduccionDetalleSegunda.PlanProduccionDetalleCantidades.Add(dbPlanProduccionDetalleCantidade);
                dbPlanProduccionDetalleCantidade.AuditFechaCreacion = DateTime.Now;
                dbPlanProduccionDetalleCantidade.AuditUserNameCreacion = serviceOptions.UserName;
            }
            return dbPlanProduccionDetalleSegunda;
        }


        public List<Desvio> GetDesvios(ServiceOptions serviceOptions, int? id, int? planProduccionId, string producto, string color, TipoDesvio? tipoDesvio, EstadoCharAprobado? estadoAprobado, int? causaDesvio, int? destinoId, int? temporadaId, int? proveedorId, DateTime? fechaDesde, DateTime? fechaHasta, DateTime? fechaDesvioDesde, DateTime? fechaDesvioHasta)
        {
            List<Desvio> desvios = new List<Desvio>();
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbPlanProdDesvio> query = ctx.DbPlanProdDesvios.FilterLogicalRemoved();

                if (id.HasValue)
                {
                    query = query.Where(d => d.Id == id.Value);
                }
                else
                {
                    if (planProduccionId.HasValue)
                    {
                        query = query.Where(d => d.PlanProduccionDetalle.PlanProduccion.Id == planProduccionId.Value);
                    }

                    if (tipoDesvio.HasValue)
                    {
                        int tipoDesvioInt = (int)tipoDesvio.Value;
                        query = query.Where(d => d.TipoMovimiento == tipoDesvioInt);
                    }

                    if (!String.IsNullOrEmpty(producto))
                    {
                        query = query.Where(d => d.PlanProduccionDetalle.Producto.ProductoIdExterno.StartsWith(producto));
                    }

                    if (!String.IsNullOrEmpty(color))
                    {
                        query = query.Where(d => d.PlanProduccionDetalle.Producto.ColorIdExterno == color);
                    }

                    if (estadoAprobado.HasValue)
                    {
                        string estadoAprobadoStr = Convert.ToString((char)estadoAprobado.Value);
                        query = query.Where(d => d.Estado == estadoAprobadoStr);
                    }

                    if (causaDesvio.HasValue)
                    {
                        query = query.Where(d => d.DesvioCausaId == causaDesvio.Value);
                    }

                    if (destinoId.HasValue)
                    {
                        query = query.Where(d => d.PlanProduccionDetalle.PlanProduccion.DestinoId == destinoId.Value);
                    }

                    if (temporadaId.HasValue)
                    {
                        query = query.Where(d => d.PlanProduccionDetalle.PlanProduccion.TemporadaId == temporadaId.Value);
                    }

                    if (proveedorId.HasValue)
                    {
                        query = query.Where(d => d.PlanProduccionDetalle.PlanProduccion.ProveedorId == proveedorId.Value);
                    }

                    
                    if (fechaDesde.HasValue)
                    {
                        DateTime fecha = fechaDesde.Value.Date;
                        query = query.Where(d => d.FechaCreacion >= fecha);
                    }

                    if (fechaHasta.HasValue)
                    {
                        DateTime fecha = fechaHasta.Value.Date.AddDays(1).AddSeconds(-1);
                        query = query.Where(d => d.FechaCreacion <= fecha);
                    }

                    if (fechaDesvioDesde.HasValue)
                    {
                        DateTime fecha = fechaDesvioDesde.Value.Date;
                        query = query.Where(d => d.FechaDesvio >= fecha);
                    }

                    if (fechaDesvioHasta.HasValue)
                    {
                        DateTime fecha = fechaDesvioHasta.Value.Date.AddDays(1).AddSeconds(-1);
                        query = query.Where(d => d.FechaDesvio <= fecha);
                    }
                }

                query.OrderBy(d => d.FechaCreacion);

                if (serviceOptions != null && serviceOptions.UsePages)
                {
                    query = query.Skip(serviceOptions.GetSkip()).Take(serviceOptions.PageSize);
                }

                var dbDesvios = query.ToList();

                foreach (var dbDesvio in dbDesvios)
                {
                    desvios.Add(GetDesvioFromDbDesvio(dbDesvio));
                }
            }

            return desvios;
        }

        public List<Desvio> SaveDesvioMasivo(ServiceOptions serviceOptions, List<Desvio> desvios)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    foreach (Desvio desvio in desvios)
                    {
                        SaveDesvio(serviceOptions, desvio);
                    }
                }

                tScope.Complete();
            }

            return desvios;
        }

        public List<Desvio> SaveYAprobarDesvioMasivo(ServiceOptions serviceOptions, List<Desvio> desvios, string userName, EstadoCharAprobado aprobado)
        {
            List<Desvio> desviosGuardados = new List<Desvio>();

            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    foreach (Desvio desvio in desvios)
                    {
                        desviosGuardados.Add(SaveDesvio(serviceOptions, desvio));
                        AprobarDesvio(serviceOptions, desvio.Id, userName, aprobado);
                    }
                }

                tScope.Complete();

            }

            return desviosGuardados;
        }

        public List<DesvioOrigen> GetDesvioOrigen(ServiceOptions serviceOptions, int desvioId)
        {
            List<DesvioOrigen> origenes = new List<DesvioOrigen>();
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                var dbDesvio = ctx.DbPlanProdDesvios.FilterLogicalRemoved().Where(d => d.Id == desvioId).SingleOrDefault();
                if (dbDesvio != null)
                {
                    var dbOrigenesList = dbDesvio.PlanProdDesvioOrigens.ToList();
                    foreach (var dbOrigen in dbOrigenesList)
                    {
                        DesvioOrigen origen = new DesvioOrigen();
                        EntityMapper.Map(dbOrigen, origen);
                        origenes.Add(origen);
                    }
                }
            }

            return origenes;
        }

        public Desvio SaveDesvio(ServiceOptions serviceOptions, Desvio desvio)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    DbPlanProdDesvio dbDesvio = ctx.DbPlanProdDesvios.Where(d => d.Id == desvio.Id).SingleOrDefault();

                    if (dbDesvio == null)
                    {
                        dbDesvio = new DbPlanProdDesvio();
                        ctx.DbPlanProdDesvios.AddObject(dbDesvio);
                        dbDesvio.AuditFechaCreacion = DateTime.Now;
                        dbDesvio.AuditUserNameCreacion = serviceOptions.UserName;
                        dbDesvio.UsuarioCreacion = desvio.UsuarioCreador;
                        dbDesvio.FechaCreacion = DateTime.Now;
                    }

                    dbDesvio.PlanProduccionDetalleId = desvio.PlanProduccionDetallePrimeraId;
                    dbDesvio.PlanProduccionDetalleSegundaId = desvio.PlanProduccionDetalleSegundaId;
                    dbDesvio.TipoMovimiento = (int)desvio.TipoDesvio;
                    dbDesvio.Estado = desvio.Estado;
                    dbDesvio.DesvioCausaId = desvio.CausaDesvioId;

                    dbDesvio.AuditUserNameModificacion = serviceOptions.UserName;
                    dbDesvio.AuditFechaModificacion = DateTime.Now;


                    // Validar si el tipo de desvio es movimiento que la suma sea igual a la original
                    if (desvio.TipoDesvio == TipoDesvio.Movimiento && !desvio.EsMovimientoValido())
                        throw new Exception("El movimiento debe mantener el total inalterado");

                    foreach (DesvioDetalle desvioDetalle in desvio.DesvioDetalles)
                    {
                        var detalleProductoOriginal = ctx.DbPlanProduccionDetalleCantidades.Where(cant => cant.Id == desvioDetalle.DetalleProductoCantidadId).Single();

                        DbPlanProdDesvioDetalle dbDesvioDetalle = dbDesvio.PlanProdDesvioDetalles.Where(de => de.DetalleCantidadesId == detalleProductoOriginal.Id).SingleOrDefault();

                        if (dbDesvioDetalle == null)
                        {
                            dbDesvioDetalle = new DbPlanProdDesvioDetalle();
                            dbDesvio.PlanProdDesvioDetalles.Add(dbDesvioDetalle);

                            dbDesvioDetalle.AuditFechaCreacion = DateTime.Now;
                            dbDesvioDetalle.AuditUserNameCreacion = serviceOptions.UserName;
                        }

                        dbDesvioDetalle.DetalleCantidadesId = desvioDetalle.DetalleProductoCantidadId;
                        dbDesvioDetalle.CantidadOriginal = detalleProductoOriginal.Cantidad;
                        dbDesvioDetalle.CantidadFinal = desvioDetalle.CantidadFinal;

                        dbDesvioDetalle.AuditFechaModificacion = DateTime.Now;
                        dbDesvioDetalle.AuditUserNameModificacion = serviceOptions.UserName;
                    }

                    ctx.SaveChanges();

                    desvio.Id = dbDesvio.Id;
                }

                tScope.Complete();
            }

            return desvio;
        }

        public void EliminarDesvio(ServiceOptions serviceOptions, int desvioId)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    DbPlanProdDesvio dbDesvio = ctx.DbPlanProdDesvios.Where(d => d.Id == desvioId).Single();
                    EstadoCharAprobado estado = (EstadoCharAprobado)dbDesvio.Estado[0];
                    if (!(estado == EstadoCharAprobado.Aprobado || estado == EstadoCharAprobado.Rechazado))
                    {
                        List<DbPlanProdDesvioDetalle> detalles = dbDesvio.PlanProdDesvioDetalles.ToList();
                        foreach (var dbDesvioDetalles in detalles)
                        {
                            ctx.DbPlanProdDesvioDetalles.DeleteObject(dbDesvioDetalles);
                        }

                        ctx.DbPlanProdDesvios.DeleteObject(dbDesvio);
                        ctx.SaveChanges();
                    }
                }

                tScope.Complete();
            }
        }

        public void AprobarDesvio(ServiceOptions serviceOptions, int desvioId, string userName, EstadoCharAprobado estado)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    DbPlanProdDesvio dbPlanProdDesvio = ctx.DbPlanProdDesvios.Where(d => d.Id == desvioId).SingleOrDefault();
                    if (dbPlanProdDesvio != null)
                    {
                        LoadDbDesvioParaAprobar(serviceOptions, desvioId, userName, estado, ctx, dbPlanProdDesvio);

                        ctx.SaveChanges();
                    }
                }

                tScope.Complete();
            }
        }

        private static void LoadDbDesvioParaAprobar(ServiceOptions serviceOptions, int desvioId, string userName, EstadoCharAprobado estado, PlanProdEntities ctx, DbPlanProdDesvio dbPlanProdDesvio)
        {
            dbPlanProdDesvio.Estado = Convert.ToString((char)estado);

            if (dbPlanProdDesvio.Estado == Convert.ToString((char)EstadoCharAprobado.Aprobado))// esta linea esta mal!!!
            {
                dbPlanProdDesvio.UsuarioAprobacion = userName;
                dbPlanProdDesvio.FechaAprobacion = DateTime.Now;

                dbPlanProdDesvio.AuditFechaModificacion = DateTime.Now;
                dbPlanProdDesvio.AuditUserNameModificacion = serviceOptions.UserName;

                foreach (DbPlanProdDesvioDetalle dbDesvioDetalle in dbPlanProdDesvio.PlanProdDesvioDetalles)
                {
                    var detalleProductoOriginal = ctx.DbPlanProduccionDetalleCantidades.Where(cant => cant.Id == dbDesvioDetalle.DetalleCantidadesId).Single();
                    detalleProductoOriginal.Cantidad = dbDesvioDetalle.CantidadFinal;

                    detalleProductoOriginal.AuditUserNameModificacion = serviceOptions.UserName;
                    detalleProductoOriginal.AuditFechaModificacion = DateTime.Now;
                }

                DbPlanProduccion planProd = (from desvio in ctx.DbPlanProdDesvios
                                             where desvio.Id == desvioId
                                             select desvio.PlanProduccionDetalle.PlanProduccion).Single();

                planProd.AuditUserNameModificacion = serviceOptions.UserName;
                planProd.AuditFechaModificacion = DateTime.Now;
            }
        }

        public List<RelacionProductoEntity> GetRelacionProducto(ServiceOptions serviceOptions, RelacionProductoSearch search)
        {
            List<RelacionProductoEntity> relacionList = new List<RelacionProductoEntity>();
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                if (search.NombreEntidad == RelacionProductoEntidadMapeo.Calidad)
                {
                    IQueryable<DbCalidad> query = ctx.DbCalidad;
                    if (!String.IsNullOrEmpty(search.CodigoExterno))
                    {
                        query = query.Where(c => c.CodigoExterno == search.CodigoExterno);
                    }
                    if (!String.IsNullOrEmpty(search.Descripcion))
                    {
                        query = query.Where(c => c.Descripcion.Contains(search.Descripcion));
                    }

                    relacionList.AddRange(query.Select(c => new RelacionProductoEntity() { NombreEntidad = search.NombreEntidad, CodigoExterno = c.CodigoExterno, Descripcion = c.Descripcion, CompanyId = c.EmpresaId }));
                }
                else if (search.NombreEntidad == RelacionProductoEntidadMapeo.Categoria)
                {
                    IQueryable<DbCategoria> query = ctx.DbCategoria;
                    if (!String.IsNullOrEmpty(search.CodigoExterno))
                    {
                        query = query.Where(c => c.CodigoExterno == search.CodigoExterno);
                    }
                    if (!String.IsNullOrEmpty(search.Descripcion))
                    {
                        query = query.Where(c => c.Descripcion.Contains(search.Descripcion));
                    }

                    relacionList.AddRange(query.Select(c => new RelacionProductoEntity() { NombreEntidad = search.NombreEntidad, CodigoExterno = c.CodigoExterno, Descripcion = c.Descripcion, CompanyId = c.EmpresaId }));
                }
                else if (search.NombreEntidad == RelacionProductoEntidadMapeo.Color)
                {
                    IQueryable<DbColor> query = ctx.DbColor;
                    if (!String.IsNullOrEmpty(search.CodigoExterno))
                    {
                        query = query.Where(c => c.CodigoExterno == search.CodigoExterno);
                    }
                    if (!String.IsNullOrEmpty(search.Descripcion))
                    {
                        query = query.Where(c => c.Descripcion.Contains(search.Descripcion));
                    }

                    relacionList.AddRange(query.Select(c => new RelacionProductoEntity() { NombreEntidad = search.NombreEntidad, CodigoExterno = c.CodigoExterno, Descripcion = c.Descripcion, CompanyId = c.EmpresaId }));
                }
                else if (search.NombreEntidad == RelacionProductoEntidadMapeo.GrupoTalle)
                {
                    IQueryable<DbGrupoTalle> query = ctx.DbGrupoTalle;
                    if (!String.IsNullOrEmpty(search.CodigoExterno))
                    {
                        query = query.Where(c => c.CodigoExterno == search.CodigoExterno);
                    }
                    if (!String.IsNullOrEmpty(search.Descripcion))
                    {
                        query = query.Where(c => c.Descripcion.Contains(search.Descripcion));
                    }

                    relacionList.AddRange(query.Select(c => new RelacionProductoEntity() { NombreEntidad = search.NombreEntidad, CodigoExterno = c.CodigoExterno, Descripcion = c.Descripcion, CompanyId = c.EmpresaId }));
                }
                else if (search.NombreEntidad == RelacionProductoEntidadMapeo.Linea)
                {
                    IQueryable<DbLinea> query = ctx.DbLinea;
                    if (!String.IsNullOrEmpty(search.CodigoExterno))
                    {
                        query = query.Where(c => c.CodigoExterno == search.CodigoExterno);
                    }
                    if (!String.IsNullOrEmpty(search.Descripcion))
                    {
                        query = query.Where(c => c.Descripcion.Contains(search.Descripcion));
                    }

                    relacionList.AddRange(query.Select(c => new RelacionProductoEntity() { NombreEntidad = search.NombreEntidad, CodigoExterno = c.CodigoExterno, Descripcion = c.Descripcion, CompanyId = c.EmpresaId }));
                }
                else if (search.NombreEntidad == RelacionProductoEntidadMapeo.Marca)
                {
                    IQueryable<DbMarca> query = ctx.DbMarca;
                    if (!String.IsNullOrEmpty(search.CodigoExterno))
                    {
                        query = query.Where(c => c.CodigoExterno == search.CodigoExterno);
                    }
                    if (!String.IsNullOrEmpty(search.Descripcion))
                    {
                        query = query.Where(c => c.Descripcion.Contains(search.Descripcion));
                    }

                    relacionList.AddRange(query.Select(c => new RelacionProductoEntity() { NombreEntidad = search.NombreEntidad, CodigoExterno = c.CodigoExterno, Descripcion = c.Descripcion, CompanyId = c.EmpresaId }));
                }
                else if (search.NombreEntidad == RelacionProductoEntidadMapeo.Origen)
                {
                    IQueryable<DbOrigen> query = ctx.DbOrigen;
                    if (!String.IsNullOrEmpty(search.CodigoExterno))
                    {
                        query = query.Where(c => c.CodigoExterno == search.CodigoExterno);
                    }
                    if (!String.IsNullOrEmpty(search.Descripcion))
                    {
                        query = query.Where(c => c.Descripcion.Contains(search.Descripcion));
                    }

                    relacionList.AddRange(query.Select(c => new RelacionProductoEntity() { NombreEntidad = search.NombreEntidad, CodigoExterno = c.CodigoExterno, Descripcion = c.Descripcion, CompanyId = c.EmpresaId }));
                }
                else if (search.NombreEntidad == RelacionProductoEntidadMapeo.SubCategoria)
                {
                    IQueryable<DbSubCategoria> query = ctx.DbSubCategoria;
                    if (!String.IsNullOrEmpty(search.CodigoExterno))
                    {
                        query = query.Where(c => c.CodigoExterno == search.CodigoExterno);
                    }
                    if (!String.IsNullOrEmpty(search.Descripcion))
                    {
                        query = query.Where(c => c.Descripcion.Contains(search.Descripcion));
                    }

                    relacionList.AddRange(query.Select(c => new RelacionProductoEntity() { NombreEntidad = search.NombreEntidad, CodigoExterno = c.CodigoExterno, Descripcion = c.Descripcion, CompanyId = c.EmpresaId }));
                }
                else if (search.NombreEntidad == RelacionProductoEntidadMapeo.Rubro)
                {
                    IQueryable<DbRubro> query = ctx.DbRubroes;
                    if (!String.IsNullOrEmpty(search.CodigoExterno))
                    {
                        query = query.Where(c => c.Id == search.CodigoExterno);
                    }
                    if (!String.IsNullOrEmpty(search.Descripcion))
                    {
                        query = query.Where(c => c.Nombre.Contains(search.Descripcion));
                    }

                    relacionList.AddRange(query.Select(c => new RelacionProductoEntity() {NombreEntidad = search.NombreEntidad, CodigoExterno = c.Id, Descripcion = c.Nombre, CompanyId = c.EmpresaId, ExtraInt_1_Valor = c.ExtensionSemanas }));
                }
            }

            return relacionList;
        }

        public void SaveRelacionProducto(RelacionProductoEntity entity)
        {
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                if (entity.NombreEntidad == RelacionProductoEntidadMapeo.Calidad)
                {
                    var dbEntity = ctx.DbCalidad.Where(c => c.CodigoExterno == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbCalidad();
                        ctx.DbCalidad.AddObject(dbEntity);
                        dbEntity.CodigoExterno = entity.CodigoExterno;
                    }
                    dbEntity.Descripcion = entity.Descripcion;
                }
                else if (entity.NombreEntidad == RelacionProductoEntidadMapeo.Categoria)
                {
                    var dbEntity = ctx.DbCategoria.Where(c => c.CodigoExterno == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbCategoria();
                        ctx.DbCategoria.AddObject(dbEntity);
                        dbEntity.CodigoExterno = entity.CodigoExterno;
                    }
                    dbEntity.Descripcion = entity.Descripcion;
                }
                else if (entity.NombreEntidad == RelacionProductoEntidadMapeo.Color)
                {
                    var dbEntity = ctx.DbColor.Where(c => c.CodigoExterno == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbColor();
                        ctx.DbColor.AddObject(dbEntity);
                        dbEntity.CodigoExterno = entity.CodigoExterno;
                    }
                    dbEntity.Descripcion = entity.Descripcion;
                }
                else if (entity.NombreEntidad == RelacionProductoEntidadMapeo.GrupoTalle)
                {
                    var dbEntity = ctx.DbGrupoTalle.Where(c => c.CodigoExterno == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbGrupoTalle();
                        ctx.DbGrupoTalle.AddObject(dbEntity);
                        dbEntity.CodigoExterno = entity.CodigoExterno;
                    }
                    dbEntity.Descripcion = entity.Descripcion;
                }
                else if (entity.NombreEntidad == RelacionProductoEntidadMapeo.Linea)
                {
                    var dbEntity = ctx.DbLinea.Where(c => c.CodigoExterno == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbLinea();
                        ctx.DbLinea.AddObject(dbEntity);
                        dbEntity.CodigoExterno = entity.CodigoExterno;
                    }
                    dbEntity.Descripcion = entity.Descripcion;
                }
                else if (entity.NombreEntidad == RelacionProductoEntidadMapeo.Marca)
                {
                    var dbEntity = ctx.DbMarca.Where(c => c.CodigoExterno == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbMarca();
                        ctx.DbMarca.AddObject(dbEntity);
                        dbEntity.CodigoExterno = entity.CodigoExterno;
                    }
                    dbEntity.Descripcion = entity.Descripcion;
                }
                else if (entity.NombreEntidad == RelacionProductoEntidadMapeo.Origen)
                {
                    var dbEntity = ctx.DbOrigen.Where(c => c.CodigoExterno == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbOrigen();
                        ctx.DbOrigen.AddObject(dbEntity);
                        dbEntity.CodigoExterno = entity.CodigoExterno;
                    }
                    dbEntity.Descripcion = entity.Descripcion;
                }
                else if (entity.NombreEntidad == RelacionProductoEntidadMapeo.SubCategoria)
                {
                    var dbEntity = ctx.DbSubCategoria.Where(c => c.CodigoExterno == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbSubCategoria();
                        ctx.DbSubCategoria.AddObject(dbEntity);
                        dbEntity.CodigoExterno = entity.CodigoExterno;
                    }
                    dbEntity.Descripcion = entity.Descripcion;
                }
                else if (entity.NombreEntidad == RelacionProductoEntidadMapeo.Rubro)
                {
                    var dbEntity = ctx.DbRubroes.Where(c => c.Id == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity == null)
                    {
                        dbEntity = new DbRubro();
                        ctx.DbRubroes.AddObject(dbEntity);
                        dbEntity.Id = entity.CodigoExterno;                        
                    }

                    dbEntity.Nombre = entity.Descripcion;
                    if (entity.ExtraInt_1_Valor.HasValue)
                    {
                        dbEntity.ExtensionSemanas = entity.ExtraInt_1_Valor.Value;
                    }
                }

                ctx.SaveChanges();
            }
        }

        public void EliminarRelacionProducto(RelacionProductoEntity entity)
        {
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                if (entity.NombreEntidad == RelacionProductoEntidadMapeo.Calidad)
                {
                    var dbEntity = ctx.DbCalidad.Where(c => c.CodigoExterno == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity != null)
                    {
                        ctx.DbCalidad.DeleteObject(dbEntity);
                    }
                }
                else if (entity.NombreEntidad == RelacionProductoEntidadMapeo.Categoria)
                {
                    var dbEntity = ctx.DbCategoria.Where(c => c.CodigoExterno == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity != null)
                    {
                        ctx.DbCategoria.DeleteObject(dbEntity);
                    }
                }
                else if (entity.NombreEntidad == RelacionProductoEntidadMapeo.Color)
                {
                    var dbEntity = ctx.DbColor.Where(c => c.CodigoExterno == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity != null)
                    {
                        ctx.DbColor.DeleteObject(dbEntity);
                    }
                }
                else if (entity.NombreEntidad == RelacionProductoEntidadMapeo.GrupoTalle)
                {
                    var dbEntity = ctx.DbGrupoTalle.Where(c => c.CodigoExterno == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity != null)
                    {
                        ctx.DbGrupoTalle.DeleteObject(dbEntity);
                    }
                }
                else if (entity.NombreEntidad == RelacionProductoEntidadMapeo.Linea)
                {
                    var dbEntity = ctx.DbLinea.Where(c => c.CodigoExterno == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity != null)
                    {
                        ctx.DbLinea.DeleteObject(dbEntity);
                    }
                }
                else if (entity.NombreEntidad == RelacionProductoEntidadMapeo.Marca)
                {
                    var dbEntity = ctx.DbMarca.Where(c => c.CodigoExterno == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity != null)
                    {
                        ctx.DbMarca.DeleteObject(dbEntity);
                    }
                }
                else if (entity.NombreEntidad == RelacionProductoEntidadMapeo.Origen)
                {
                    var dbEntity = ctx.DbOrigen.Where(c => c.CodigoExterno == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity != null)
                    {
                        ctx.DbOrigen.DeleteObject(dbEntity);
                    }
                }
                else if (entity.NombreEntidad == RelacionProductoEntidadMapeo.SubCategoria)
                {
                    var dbEntity = ctx.DbSubCategoria.Where(c => c.CodigoExterno == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity != null)
                    {
                        ctx.DbSubCategoria.DeleteObject(dbEntity);
                    }
                }
                else if (entity.NombreEntidad == RelacionProductoEntidadMapeo.Rubro)
                {
                    var dbEntity = ctx.DbRubroes.Where(c => c.Id == entity.CodigoExterno).SingleOrDefault();
                    if (dbEntity != null)
                    {
                        ctx.DbRubroes.DeleteObject(dbEntity);
                    }
                }

                ctx.SaveChanges();
            }
        }

        public List<Destino> GetDestinos(ServiceOptions serviceOptions, int empresaId, string nombreLike)
        {
            List<Destino> destinoList = new List<Destino>();

            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbDestino> query = ctx.DbDestinoes.Where(d => d.EmpresaId == empresaId);

                if (!String.IsNullOrEmpty(nombreLike))
                {
                    query = query.Where(d => d.Nombre.Contains(nombreLike));
                }

                query = query.OrderBy(d => d.Nombre);

                if (serviceOptions != null && serviceOptions.UsePages)
                {
                    query = query.Skip(serviceOptions.GetSkip()).Take(serviceOptions.PageSize);
                }

                // Filtro los destinos los destinos
                if (!serviceOptions.IsAdmin)
                {
                    query = query.Where(d => serviceOptions.Operations.Contains(d.SecurityKey));
                }

                foreach (var dbDestino in query.ToList())
                {
                    Destino d = new Destino();
                    EntityMapper.Map(dbDestino, d);
                    destinoList.Add(d);
                }
            }

            return destinoList;
        }

        public Destino GetDestinoById(ServiceOptions serviceOptions, int destinoId)
        {
            Destino destino = new Destino();
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbDestino> query = ctx.DbDestinoes.Where(d => d.Id == destinoId).FilterLogicalRemoved();

                var dbDestino = query.Single();

                if (serviceOptions.IsAdmin || serviceOptions.Operations.Contains(dbDestino.SecurityKey))
                {
                    EntityMapper.Map(dbDestino, destino);
                }
            }

            return destino;
        }

        public Destino SaveDestino(ServiceOptions serviceOptions, Destino destino)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    DbDestino dbDestino;

                    dbDestino = ctx.DbDestinoes.Where(t => t.Id == destino.Id).SingleOrDefault();
                    if (dbDestino == null)
                    {
                        dbDestino = new DbDestino();
                        ctx.DbDestinoes.AddObject(dbDestino);
                        dbDestino.AuditFechaCreacion = DateTime.Now;
                        dbDestino.AuditUserNameCreacion = serviceOptions.UserName;
                    }
                    else
                    {
                        dbDestino.AuditFechaModificacion = DateTime.Now;
                        dbDestino.AuditUserNameModificacion = serviceOptions.UserName;
                    }

                    dbDestino.EmpresaId = destino.EmpresaId;
                    dbDestino.Nombre = destino.Nombre;
                    dbDestino.CodigoExterno = destino.CodigoExterno;
                    dbDestino.MapeoDestinoExterno = destino.MapeoDestinoExterno;
                    dbDestino.SecurityKey = destino.SecurityKey;

                    ctx.SaveChanges();
                    destino.Id = dbDestino.Id;
                }

                tScope.Complete();
                return destino;
            }
        }

        public void EliminarDestino(ServiceOptions serviceOptions, int destinoId)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    var destino = ctx.DbDestinoes.Where(t => t.Id == destinoId).Single();
                    ctx.DbDestinoes.DeleteObject(destino);
                    ctx.SaveChanges();
                }

                tScope.Complete();
            }
        }

        public List<Proveedor> GetProveedores(ServiceOptions serviceOptions, SearchProveedorCriteria criteria)
        {
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbProveedor> query = ctx.DbProveedors.FilterLogicalRemoved();

                if (criteria.Id.HasValue)
                {
                    query = query.Where(p => p.Id == criteria.Id.Value);
                }

                if (!String.IsNullOrEmpty(criteria.RazonSocial))
                {
                    query = query.Where(p => p.RazonSocial.Contains(criteria.RazonSocial));
                }

                query = query.Where(p => p.EmpresaId == criteria.EmpresaId);

                query = query.OrderBy(p => p.RazonSocial);

                if (serviceOptions != null && serviceOptions.UsePages)
                {
                    query = query.Skip(serviceOptions.GetSkip()).Take(serviceOptions.PageSize);
                }

                return (from p in query
                        select new Proveedor()
                        {
                            Id = p.Id,
                            EmpresaId = p.EmpresaId,
                            ProveedorIdExterno = p.ProveedorIdExterno,
                            RazonSocial = p.RazonSocial
                        }).ToList();
            }
        }

        public List<PedidoComercial> GetPedidosComerciales(ServiceOptions serviceOptions, int? pedidoId, int? temporadaId, int? destinoId, DateTime? fechaDesde, DateTime? fechaHasta, string nombreLike)
        {
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbPedidoComercial> query = ctx.DbPedidoComercials.FilterLogicalRemoved();
                if (pedidoId.HasValue)
                {
                    query = query.Where(p => p.Id == pedidoId.Value);
                }
                if (temporadaId.HasValue)
                {
                    query = query.Where(p => p.TemporadaId == temporadaId.Value);
                }
                if (destinoId.HasValue)
                {
                    query = query.Where(p => p.DestinoId == destinoId.Value);
                }
                if (fechaDesde.HasValue)
                {
                    query = query.Where(p => p.AuditFechaModificacion.Value >= fechaDesde.Value);
                }
                if (fechaHasta.HasValue)
                {
                    query = query.Where(p => p.AuditFechaModificacion.Value <= fechaHasta.Value);
                }
                if (!String.IsNullOrEmpty(nombreLike))
                {
                    query = query.Where(p => p.Nombre.Contains(nombreLike));
                }

                query = query.OrderBy(p => p.Nombre);

                if (serviceOptions != null && serviceOptions.UsePages)
                {
                    query = query.Skip(serviceOptions.GetSkip()).Take(serviceOptions.PageSize);
                }

                if (!serviceOptions.IsAdmin)
                {
                    query = query.Where(d => serviceOptions.Operations.Contains(d.Destino.SecurityKey));
                }

                return (from p in query
                        select new PedidoComercial()
                        {
                            Id = p.Id,
                            DestinoId = p.DestinoId,
                            DestinoNombre = p.Destino.Nombre,
                            DestinoCodigoExterno = p.Destino.CodigoExterno,
                            TemporadaId = p.TemporadaId,
                            TemporadaNombre = p.Temporada.Nombre,
                            TemporadaCodigoExterno = p.Temporada.CodigoExterno,
                            EmpresaId = p.EmpresaId,
                            Nombre = p.Nombre,
                            CantidadPrendas = p.PedidoComercialDetalles.Sum(pd => pd.Cantidad),
                            AuditFechaCreacion = p.AuditFechaCreacion,
                            AuditFechaModificacion = p.AuditFechaModificacion,
                            AuditUserNameCreacion = p.AuditUserNameCreacion,
                            AuditUserNameModificacion = p.AuditUserNameModificacion
                        }).ToList();
            }
        }

        public PedidoComercial GetPedidoComercialById(ServiceOptions serviceOptions, int id)
        {
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                PedidoComercial pedidoComecial = (from p in ctx.DbPedidoComercials.FilterLogicalRemoved()
                                                  where p.Id == id
                                                  select new PedidoComercial()
                                                  {
                                                      Id = p.Id,
                                                      DestinoId = p.DestinoId,
                                                      DestinoNombre = p.Destino.Nombre,
                                                      DestinoCodigoExterno = p.Destino.CodigoExterno,
                                                      TemporadaId = p.TemporadaId,
                                                      TemporadaNombre = p.Temporada.Nombre,
                                                      TemporadaCodigoExterno = p.Temporada.CodigoExterno,
                                                      EmpresaId = p.EmpresaId,
                                                      CantidadPrendas = p.PedidoComercialDetalles.Sum(pd => pd.Cantidad),
                                                      Nombre = p.Nombre,
                                                      AuditFechaCreacion = p.AuditFechaCreacion,
                                                      AuditFechaModificacion = p.AuditFechaModificacion,
                                                      AuditUserNameCreacion = p.AuditUserNameCreacion,
                                                      AuditUserNameModificacion = p.AuditUserNameModificacion
                                                  }).Single();

                var detalles = from d in ctx.DbPedidoComercialDetalles
                               where d.PedidoComercialId == pedidoComecial.Id
                               select new PedidoComercialDetalle()
                               {
                                   Id = d.Id,
                                   PedidoComercialId = d.PedidoComercialId,
                                   ProductoId = d.ProductoId,
                                   ProductoIdExterno = d.Producto.ProductoIdExterno,
                                   ProductoNombre = d.Producto.ProductoNombre,
                                   ColorId = d.Producto.ColorIdExterno,
                                   ColorNombre = d.Producto.Color.Descripcion,
                                   Cantidad = d.Cantidad,
                                   AuditFechaCreacion = d.AuditFechaCreacion,
                                   AuditFechaModificacion = d.AuditFechaModificacion,
                                   AuditUserNameCreacion = d.AuditUserNameCreacion,
                                   AuditUserNameModificacion = d.AuditUserNameModificacion
                               };

                pedidoComecial.Detalle.AddRange(detalles.ToList());

                return pedidoComecial;
            }
        }

        public void EliminarPedidoComercial(ServiceOptions serviceOptions, int pedidoComercialId)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    var pedidoComercial = ctx.DbPedidoComercials.Where(p => p.Id == pedidoComercialId).Single();
                    pedidoComercial.PedidoComercialDetalles.Clear();
                    ctx.DbPedidoComercials.DeleteObject(pedidoComercial);
                    ctx.SaveChanges();
                }

                tScope.Complete();
            }
        }

        public void EliminarPedidoComercialDetalleAll(ServiceOptions serviceOptions, int pedidoComercialId)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    var pedidoComercial = ctx.DbPedidoComercials.Where(p => p.Id == pedidoComercialId).Single();
                    var pedidoComercialDetalleList = pedidoComercial.PedidoComercialDetalles.ToList();
                    pedidoComercial.PedidoComercialDetalles.Clear();
                    foreach (var detalle in pedidoComercialDetalleList)
                    {
                        ctx.DbPedidoComercialDetalles.DeleteObject(detalle);
                    }

                    ctx.SaveChanges();
                }

                tScope.Complete();
            }
        }

        public PedidoComercial SavePedidoComercial(ServiceOptions serviceOptions, PedidoComercial pedidoComercial)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    // Debería hacer un update, pero en este caso solo se usa para crear pedidos
                    DbPedidoComercial dbPedidoComercial = ctx.DbPedidoComercials.Where(p => p.Id == pedidoComercial.Id).SingleOrDefault();

                    if (dbPedidoComercial == null)
                    {
                        dbPedidoComercial = new DbPedidoComercial();
                        ctx.DbPedidoComercials.AddObject(dbPedidoComercial);
                        dbPedidoComercial.AuditUserNameCreacion = serviceOptions.UserName;
                        dbPedidoComercial.AuditFechaCreacion = DateTime.Now;
                        dbPedidoComercial.AuditUserNameModificacion = serviceOptions.UserName;
                        dbPedidoComercial.AuditFechaModificacion = DateTime.Now;
                    }
                    else
                    {
                        dbPedidoComercial.AuditUserNameModificacion = serviceOptions.UserName;
                        dbPedidoComercial.AuditFechaModificacion = DateTime.Now;
                    }

                    dbPedidoComercial.Nombre = pedidoComercial.Nombre;

                    if (pedidoComercial.TemporadaId == 0 && !string.IsNullOrEmpty(pedidoComercial.TemporadaCodigoExterno))
                    {
                        pedidoComercial.TemporadaId = ctx.DbTemporadas.Where(t => t.CodigoExterno == pedidoComercial.TemporadaCodigoExterno).Select(t => t.Id).Single();
                    }

                    dbPedidoComercial.TemporadaId = pedidoComercial.TemporadaId;

                    if (pedidoComercial.DestinoId == 0 && !String.IsNullOrEmpty(pedidoComercial.DestinoCodigoExterno))
                    {
                        pedidoComercial.DestinoId = ctx.DbDestinoes.Where(d => d.CodigoExterno == pedidoComercial.DestinoCodigoExterno).Select(d => d.Id).Single();
                    }

                    dbPedidoComercial.DestinoId = pedidoComercial.DestinoId;
                    dbPedidoComercial.EmpresaId = pedidoComercial.EmpresaId;

                    List<DbPedidoComercialDetalle> dbNewPedidoComercialDetalleList = new List<DbPedidoComercialDetalle>();
                    foreach (PedidoComercialDetalle pedidoComercialDetalle in pedidoComercial.Detalle)
                    {
                        DbPedidoComercialDetalle dbPedidoComercialDetalle = dbPedidoComercial.PedidoComercialDetalles.Where(d => d.Producto.ColorIdExterno == pedidoComercialDetalle.ColorId && d.Producto.ProductoIdExterno == pedidoComercialDetalle.ProductoIdExterno).SingleOrDefault();
                        if (dbPedidoComercialDetalle == null)
                        {
                            dbPedidoComercialDetalle = new DbPedidoComercialDetalle();
                            dbPedidoComercialDetalle.ProductoId = GetProductoIdFromProductoColor(ctx, pedidoComercialDetalle.ProductoIdExterno, pedidoComercialDetalle.ColorId);
                            dbPedidoComercialDetalle.Cantidad = pedidoComercialDetalle.Cantidad;
                            dbPedidoComercialDetalle.AuditUserNameCreacion = serviceOptions.UserName;
                            dbPedidoComercialDetalle.AuditFechaCreacion = DateTime.Now;
                            dbNewPedidoComercialDetalleList.Add(dbPedidoComercialDetalle);
                        }
                        else
                        {
                            dbPedidoComercialDetalle.Cantidad += pedidoComercialDetalle.Cantidad;

                            dbPedidoComercialDetalle.AuditUserNameModificacion = serviceOptions.UserName;
                            dbPedidoComercialDetalle.AuditFechaModificacion = DateTime.Now;
                        }
                    }

                    foreach (var dbNewDetalle in dbNewPedidoComercialDetalleList)
                    {
                        dbPedidoComercial.PedidoComercialDetalles.Add(dbNewDetalle);
                    }

                    if (serviceOptions.IsAdmin || serviceOptions.Operations.Contains(dbPedidoComercial.Destino.SecurityKey))
                    {
                        ctx.SaveChanges();
                    }

                    pedidoComercial.Id = dbPedidoComercial.Id;
                    tScope.Complete();

                }
            }

            return pedidoComercial;
        }

        public void UpdatePedidoComercialDetalle(ServiceOptions serviceOptions, List<PedidoComercialDetalle> pedidoComercialDetalleList)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    if (pedidoComercialDetalleList.Count() > 0)
                    {
                        int pedidoComercialId = pedidoComercialDetalleList.First().PedidoComercialId;
                        DbPedidoComercial dbPedidoComercial = ctx.DbPedidoComercials.Where(p => p.Id == pedidoComercialId).Single();

                        dbPedidoComercial.AuditUserNameModificacion = serviceOptions.UserName;
                        dbPedidoComercial.AuditFechaModificacion = DateTime.Now;

                        List<DbPedidoComercialDetalle> dbNewPedidoComercialDetalleList = new List<DbPedidoComercialDetalle>();
                        foreach (PedidoComercialDetalle pedidoComercialDetalle in pedidoComercialDetalleList)
                        {
                            DbPedidoComercialDetalle dbPedidoComercialDetalle = dbPedidoComercial.PedidoComercialDetalles.Where(d => d.Producto.ColorIdExterno == pedidoComercialDetalle.ColorId && d.Producto.ProductoIdExterno == pedidoComercialDetalle.ProductoIdExterno).SingleOrDefault();
                            if (dbPedidoComercialDetalle == null)
                            {
                                dbPedidoComercialDetalle = new DbPedidoComercialDetalle();
                                dbPedidoComercialDetalle.ProductoId = GetProductoIdFromProductoColor(ctx, pedidoComercialDetalle.ProductoIdExterno, pedidoComercialDetalle.ColorId);
                                dbPedidoComercialDetalle.Cantidad = pedidoComercialDetalle.Cantidad;
                                dbPedidoComercialDetalle.AuditUserNameCreacion = serviceOptions.UserName;
                                dbPedidoComercialDetalle.AuditFechaCreacion = DateTime.Now;
                                dbNewPedidoComercialDetalleList.Add(dbPedidoComercialDetalle);
                            }
                            else
                            {
                                dbPedidoComercialDetalle.Cantidad += pedidoComercialDetalle.Cantidad;
                                dbPedidoComercialDetalle.AuditUserNameModificacion = serviceOptions.UserName;
                                dbPedidoComercialDetalle.AuditFechaModificacion = DateTime.Now;
                            }
                        }

                        foreach (var dbNewDetalle in dbNewPedidoComercialDetalleList)
                        {
                            dbPedidoComercial.PedidoComercialDetalles.Add(dbNewDetalle);
                        }

                        ctx.SaveChanges();
                    }
                }

                tScope.Complete();
            }
        }

        public void EliminarPedidoComercialDetalle(ServiceOptions serviceOptions, int pedidoComercialDetalleId)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    var pedidoComercialDetalle = ctx.DbPedidoComercialDetalles.Where(d => d.Id == pedidoComercialDetalleId).Single();
                    ctx.DbPedidoComercialDetalles.DeleteObject(pedidoComercialDetalle);
                    ctx.SaveChanges();
                }

                tScope.Complete();
            }
        }

        public List<PresupuestoProduccion> GetPresupuestoProduccion(ServiceOptions serviceOptions, int? presupuestoId, string nombreLike, int? temporadaId, int? destinoId, int? proveedorId, EstadoAprobado? estado, DateTime? fechaDesde, DateTime? fechaHasta)
        {
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbPresupuestoProduccion> query = ctx.DbPresupuestoProduccions.FilterLogicalRemoved();

                if (presupuestoId.HasValue)
                {
                    query = query.Where(p => p.Id == presupuestoId.Value);
                }
                else
                {
                    if (!String.IsNullOrEmpty(nombreLike))
                    {
                        query = query.Where(p => p.Nombre.Contains(nombreLike));
                    }

                    if (temporadaId.HasValue)
                    {
                        query = query.Where(p => p.TemporadaId == temporadaId.Value);
                    }
                    if (destinoId.HasValue)
                    {
                        query = query.Where(p => p.DestinoId == destinoId.Value);
                    }

                    if (proveedorId.HasValue)
                    {
                        query = query.Where(p => p.ProveedorId == proveedorId.Value);
                    }

                    if (estado.HasValue)
                    {
                        if (estado.Value == EstadoAprobado.NoDefinido)
                        {
                            query = query.Where(p => p.Aprobado == null);
                        }
                        else
                        {
                            bool aprobado = estado.Value == EstadoAprobado.Aprobado;
                            query = query.Where(p => p.Aprobado == aprobado);
                        }
                    }

                    if (fechaDesde.HasValue)
                    {
                        query = query.Where(p => p.AuditFechaModificacion.Value >= fechaDesde.Value);
                    }
                    if (fechaHasta.HasValue)
                    {
                        query = query.Where(p => p.AuditFechaModificacion.Value <= fechaHasta.Value);
                    }
                }

                if (!serviceOptions.IsAdmin)
                {
                    query = query.Where(d => serviceOptions.Operations.Contains(d.Destino.SecurityKey));
                }

                query.OrderBy(p => p.Id);

                if (serviceOptions != null && serviceOptions.UsePages)
                {
                    query = query.Skip(serviceOptions.GetSkip()).Take(serviceOptions.PageSize);
                }

                List<PresupuestoProduccion> presupuestosDeProduccion = new List<PresupuestoProduccion>();
                presupuestosDeProduccion.AddRange((from p in query
                                                   select new PresupuestoProduccion()
                                                   {
                                                       Id = p.Id,
                                                       DestinoId = p.DestinoId,
                                                       DestinoNombre = p.Destino.Nombre,
                                                       DestinoCodigoExterno = p.Destino.CodigoExterno,
                                                       Nombre = p.Nombre,
                                                       TemporadaId = p.TemporadaId,
                                                       TemporadaNombre = p.Temporada.Nombre,
                                                       TemporadaCodigoExterno = p.Temporada.CodigoExterno,
                                                       EmpresaId = p.EmpresaId,
                                                       ProveedorId = p.ProveedorId,
                                                       ProveedorIdExterno = p.Proveedor.ProveedorIdExterno,
                                                       ProveedorNombre = p.Proveedor.RazonSocial,
                                                       EstadoBool = p.Aprobado,
                                                       PlanProduccionId = p.PlanProduccionId,
                                                       AuditFechaCreacion = p.AuditFechaCreacion,
                                                       AuditFechaModificacion = p.AuditFechaModificacion,
                                                       AuditUserNameCreacion = p.AuditUserNameCreacion,
                                                       AuditUserNameModificacion = p.AuditUserNameModificacion
                                                   }).ToList());

                presupuestosDeProduccion.ForEach(p => p.Estado = p.EstadoBool.HasValue ? (p.EstadoBool.Value ? EstadoAprobado.Aprobado : EstadoAprobado.NoAprobado) : EstadoAprobado.NoDefinido);

                return presupuestosDeProduccion;
            }
        }

        public void EliminarPresupuestoProduccion(ServiceOptions serviceOptions, int presupuestoProduccionId)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {                   
                    var presupuestoProduccion = ctx.DbPresupuestoProduccions.Where(d => d.Id == presupuestoProduccionId).Single();
                    if (!presupuestoProduccion.Aprobado.HasValue || !presupuestoProduccion.Aprobado.Value)
                    {
                        ctx.PresupuestoProduccionEliminar(presupuestoProduccionId);
                    }
                }

                tScope.Complete();
            }
        }

        public void AprobarPresupuestoProduccion(ServiceOptions serviceOptions, int presupuestoProduccionId, int empresaId, string userName, bool aprobado)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {                                        
                    var presupuestoProduccion = ctx.DbPresupuestoProduccions.Where(d => d.Id == presupuestoProduccionId).Single();
                    if (!presupuestoProduccion.Aprobado.HasValue)
                    {
                        // No debe tener cantidades en cero
                        foreach (var ppDetalles in presupuestoProduccion.PresupuestoProduccionDetalles)
                        {
                            bool unaDistintaACero = false;
                            foreach (var ppCant in ppDetalles.PresupuestoProduccionDetalleCantidades)
                            {
                                if (ppCant.Cantidad != 0)
                                {
                                    unaDistintaACero = true;
                                    break;
                                }
                            }

                            if (!unaDistintaACero)
                            {
                                throw new Exception("Existen productos en el presupuesto sin ninguna cantidad asignada");
                            }
                        }

                        presupuestoProduccion.Aprobado = aprobado;
                        presupuestoProduccion.UsuarioAprobacion = userName;
                        presupuestoProduccion.FechaAprobacion = DateTime.Now;
                        presupuestoProduccion.AuditUserNameModificacion = serviceOptions.UserName;
                        presupuestoProduccion.AuditFechaModificacion = DateTime.Now;

                        if (aprobado)
                        {
                            // Generar Plan de Producción
                            DbPlanProduccion dbPlanDeProduccion = new DbPlanProduccion();
                            ctx.DbPlanProduccions.AddObject(dbPlanDeProduccion);
                            dbPlanDeProduccion.Nombre = presupuestoProduccion.Nombre;
                            dbPlanDeProduccion.TemporadaId = presupuestoProduccion.TemporadaId;
                            dbPlanDeProduccion.ProveedorId = presupuestoProduccion.ProveedorId;
                            dbPlanDeProduccion.DestinoId = presupuestoProduccion.DestinoId;
                            dbPlanDeProduccion.EmpresaId = presupuestoProduccion.EmpresaId;
                            dbPlanDeProduccion.AuditFechaCreacion = DateTime.Now;
                            dbPlanDeProduccion.AuditUserNameCreacion = serviceOptions.UserName;

                            ctx.SaveChanges();
                            presupuestoProduccion.PlanProduccionId = dbPlanDeProduccion.Id;

                            // Creación de detalles
                            foreach (DbPresupuestoProduccionDetalle dbPresupuestoProduccionDetalle in presupuestoProduccion.PresupuestoProduccionDetalles)
                            {
                                DbPlanProduccionDetalle dbPlanProduccionDetalle = new DbPlanProduccionDetalle();
                                //ctx.DbPlanProduccionDetalles.AddObject(dbPlanProduccionDetalle);
                                dbPlanProduccionDetalle.ProductoId = dbPresupuestoProduccionDetalle.ProductoId;
                                dbPlanProduccionDetalle.AuditFechaCreacion = DateTime.Now;
                                dbPlanProduccionDetalle.AuditUserNameCreacion = serviceOptions.UserName;
                                dbPlanDeProduccion.PlanProduccionDetalles.Add(dbPlanProduccionDetalle);

                                // Cantidades por semana
                                foreach (DbPresupuestoProduccionDetalleCantidade dDbPresupuestoProduccionDetalleCantidade in dbPresupuestoProduccionDetalle.PresupuestoProduccionDetalleCantidades)
                                {
                                    DbPlanProduccionDetalleCantidade dbPlanProduccionDetalleCantidade = new DbPlanProduccionDetalleCantidade();
                                    dbPlanProduccionDetalleCantidade.NumeroSemana = dDbPresupuestoProduccionDetalleCantidade.NumeroSemana;
                                    dbPlanProduccionDetalleCantidade.Cantidad = dDbPresupuestoProduccionDetalleCantidade.Cantidad;
                                    dbPlanProduccionDetalleCantidade.AuditFechaCreacion = DateTime.Now;
                                    dbPlanProduccionDetalleCantidade.AuditUserNameCreacion = serviceOptions.UserName;
                                    dbPlanProduccionDetalle.PlanProduccionDetalleCantidades.Add(dbPlanProduccionDetalleCantidade);
                                }
                            }
                        }

                        ctx.SaveChanges();
                    }
                }

                tScope.Complete();
            }
        }

        public void UpdatePresupuestoProduccionDetalle(ServiceOptions serviceOptions, List<PresupuestoProduccionDetalleProd> presupuestoProduccionDetalles)
        {

            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    if (presupuestoProduccionDetalles.Count() > 0)
                    {
                        int presupuestoProduccionId = presupuestoProduccionDetalles.First().PresupuestoProduccionId;
                        DbPresupuestoProduccion dbPresupuestoProduccion = ctx.DbPresupuestoProduccions.Where(p => p.Id == presupuestoProduccionId).Single();

                        if (!dbPresupuestoProduccion.Aprobado.HasValue)
                        {
                            SaveDetallePresupuestoProduccion(serviceOptions, ctx, dbPresupuestoProduccion, presupuestoProduccionDetalles);

                            ctx.SaveChanges();
                        }
                    }
                }

                tScope.Complete();
            }
        }

        private void SaveDetallePresupuestoProduccion(ServiceOptions serviceOptions, PlanProdEntities ctx, DbPresupuestoProduccion dbPresupuestoProduccion, List<PresupuestoProduccionDetalleProd> presupuestoProduccionDetalles)
        {
            // Elimino todo lo que habia
            if (!dbPresupuestoProduccion.Aprobado.HasValue)
            {
                DbPresupuestoProduccionDetalle dbDetalle;
                while (dbPresupuestoProduccion.PresupuestoProduccionDetalles.Count > 0)
                {
                    dbPresupuestoProduccion.AuditUserNameModificacion = serviceOptions.UserName;
                    dbPresupuestoProduccion.AuditFechaModificacion = DateTime.Now;

                    dbDetalle = dbPresupuestoProduccion.PresupuestoProduccionDetalles.First();
                    DbPresupuestoProduccionDetalleCantidade dbDetalleCantidad;
                    while (dbDetalle.PresupuestoProduccionDetalleCantidades.Count > 0)
                    {
                        dbDetalleCantidad = dbDetalle.PresupuestoProduccionDetalleCantidades.First();
                        ctx.DbPresupuestoProduccionDetalleCantidades.DeleteObject(dbDetalleCantidad);
                    }

                    dbDetalle.PresupuestoProduccionDetalleCantidades.Clear();

                    ctx.DbPresupuestoProduccionDetalles.DeleteObject(dbDetalle);
                }

                dbPresupuestoProduccion.PresupuestoProduccionDetalles.Clear();

                ctx.SaveChanges();

                // Cargo lo nuevo
                DbTemporada dbTemporada = ctx.DbTemporadas.Where(t => t.Id == dbPresupuestoProduccion.TemporadaId).Single();

                // Generar la traducción por semanas
                if (presupuestoProduccionDetalles != null && presupuestoProduccionDetalles.Count > 0)
                {
                    HybridDictionary indiceDeSemanas = GetIndiceSemanas(dbTemporada, presupuestoProduccionDetalles.FirstOrDefault());

                    foreach (PresupuestoProduccionDetalleProd ppProd in presupuestoProduccionDetalles)
                    {
                        DbPresupuestoProduccionDetalle dbPPDetalle = new DbPresupuestoProduccionDetalle();
                        dbPPDetalle.AuditFechaCreacion = DateTime.Now;
                        dbPPDetalle.AuditUserNameCreacion = serviceOptions.UserName;
                        // Encontrar el producto

                        dbPPDetalle.ProductoId = GetProductoIdFromProductoColor(ctx, ppProd.ProductoIdExterno, ppProd.ColorId);
                        //ctx.DbPresupuestoProduccionDetalles.AddObject(dbPPDetalle);

                        dbPresupuestoProduccion.PresupuestoProduccionDetalles.Add(dbPPDetalle);
                        if (dbTemporada.NumeroSemanas != ppProd.CantidadesPorSemana.Count)
                            throw new SvcBusinessException(string.Format("Las cantidades por semana no coinciden con las de la temporada {0}", dbTemporada.Nombre));

                        foreach (PresupuestoProduccionDetalleProdSemanal ppProdCantSemana in ppProd.CantidadesPorSemana)
                        {
                            DbPresupuestoProduccionDetalleCantidade dbCantidadPorSemana = new DbPresupuestoProduccionDetalleCantidade();
                            dbCantidadPorSemana.NumeroSemana = Convert.ToInt32(indiceDeSemanas[ppProdCantSemana.NumeroSemana]);
                            dbCantidadPorSemana.Cantidad = ppProdCantSemana.Cantidad;
                            dbCantidadPorSemana.AuditFechaCreacion = DateTime.Now;
                            dbCantidadPorSemana.AuditUserNameCreacion = serviceOptions.UserName;
                            dbPPDetalle.PresupuestoProduccionDetalleCantidades.Add(dbCantidadPorSemana);
                        }
                    }
                }
            }
        }

        private HybridDictionary GetIndiceSemanas(DbTemporada dbTemporada, PresupuestoProduccionDetalleProd presupuestoProduccionDetalleProd)
        {
            HybridDictionary hdictionary = new HybridDictionary();

            // En funcion si los numeros de semana no coinciden los ordeno y los hago coincidir
            List<DbTemporadaSemanaMes> temporadaDetalleList = dbTemporada.TemporadaSemanaMes.ToList();
            temporadaDetalleList.Sort((x, y) =>
            {
                if (x.Anio == y.Anio)
                {
                    return x.NumeroSemana - y.NumeroSemana;
                }
                else
                {
                    return x.Anio - y.Anio;
                }
            });

            List<PresupuestoProduccionDetalleProdSemanal> cantidadesPorSemanaList = presupuestoProduccionDetalleProd.CantidadesPorSemana.ToList();
            cantidadesPorSemanaList.Sort((x, y) => x.NumeroSemana - y.NumeroSemana);

            // Me fijo si coinciden las semanas con el presupuesto, sino, asigno al presupuesto las semanas correspondientes            
            int i = 0;
            while (i < temporadaDetalleList.Count)
            {
                var dbTemporadaDetalle = temporadaDetalleList[i];
                var presuDetalle = cantidadesPorSemanaList[i];

                hdictionary.Add(presuDetalle.NumeroSemana, dbTemporadaDetalle.NumeroSemana);
                i++;
            }

            return hdictionary;
        }

        private int GetProductoIdFromProductoColor(PlanProdEntities ctx, string productoIdExterno, string colorIdExterno)
        {
            return (from p in ctx.DbProductoes.FilterLogicalRemoved()
                    where p.ProductoIdExterno == productoIdExterno
                    && p.ColorIdExterno == colorIdExterno
                    select p.Id).Single();
        }

        public void SavePresupuestoProduccionList(ServiceOptions serviceOptions, List<PresupuestoProduccion> presupuestoProduccionList)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    int i = 0;
                    foreach (PresupuestoProduccion presupuestoProduccion in presupuestoProduccionList)
                    {
                        DbPresupuestoProduccion dbPresupuestoProduccion = null;

                        // Asignar el proveedor y el producto
                        presupuestoProduccion.Nombre = serviceOptions.UserName + "_" + i.ToString() + "_" + DateTime.Now.ToString("yyyyMMdd_HHmm");

                        var proveedor = ctx.DbProveedors.Where(p => p.ProveedorIdExterno == presupuestoProduccion.ProveedorIdExterno).SingleOrDefault();
                        if (proveedor == null)
                            throw new SvcBusinessException(string.Format("El proveedor {0} no se encuentra en la base", presupuestoProduccion.ProveedorIdExterno));
                        else
                        {
                            presupuestoProduccion.ProveedorId = proveedor.Id;
                        }

                        dbPresupuestoProduccion = SavePresupuestoProduccion(serviceOptions, presupuestoProduccion, ctx, dbPresupuestoProduccion);
                        i++;
                    }
                }

                tScope.Complete();
            }
        }

        public PresupuestoProduccion SavePresupuestoProduccion(ServiceOptions serviceOptions, PresupuestoProduccion presupuestoProduccion)
        {
            bool guardar = true;
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    DbPresupuestoProduccion dbPresupuestoProduccion = ctx.DbPresupuestoProduccions.Where(p => p.Id == presupuestoProduccion.Id).SingleOrDefault();

                    // hack para actualizar solo el nombre
                    if (dbPresupuestoProduccion != null && presupuestoProduccion.Id != 0)
                    {
                        if (dbPresupuestoProduccion.Nombre != presupuestoProduccion.Nombre)
                        {
                            dbPresupuestoProduccion.Nombre = presupuestoProduccion.Nombre;
                            ctx.SaveChanges();
                            guardar = false;
                        }
                    }

                    if (guardar)
                    {
                        dbPresupuestoProduccion = SavePresupuestoProduccion(serviceOptions, presupuestoProduccion, ctx, dbPresupuestoProduccion);
                    }
                }

                tScope.Complete();
                return presupuestoProduccion;
            }
        }

        private DbPresupuestoProduccion SavePresupuestoProduccion(ServiceOptions serviceOptions, PresupuestoProduccion presupuestoProduccion, PlanProdEntities ctx, DbPresupuestoProduccion dbPresupuestoProduccion)
        {
            if (dbPresupuestoProduccion == null)
            {
                dbPresupuestoProduccion = new DbPresupuestoProduccion();
                ctx.DbPresupuestoProduccions.AddObject(dbPresupuestoProduccion);
                dbPresupuestoProduccion.AuditUserNameCreacion = serviceOptions.UserName;
                dbPresupuestoProduccion.AuditFechaCreacion = DateTime.Now;
            }
            else
            {
                dbPresupuestoProduccion.AuditUserNameModificacion = serviceOptions.UserName;
                dbPresupuestoProduccion.AuditFechaModificacion = DateTime.Now;
            }

            if (!dbPresupuestoProduccion.Aprobado.HasValue)
            {
                dbPresupuestoProduccion.Nombre = presupuestoProduccion.Nombre;
                if (presupuestoProduccion.TemporadaId == 0 && !String.IsNullOrEmpty(presupuestoProduccion.TemporadaCodigoExterno))
                {
                    presupuestoProduccion.TemporadaId = ctx.DbTemporadas.Where(t => t.CodigoExterno == presupuestoProduccion.TemporadaCodigoExterno).Select(s => s.Id).Single();
                }

                dbPresupuestoProduccion.TemporadaId = presupuestoProduccion.TemporadaId;
                dbPresupuestoProduccion.ProveedorId = presupuestoProduccion.ProveedorId;

                if (presupuestoProduccion.DestinoId == 0 && !String.IsNullOrEmpty(presupuestoProduccion.DestinoCodigoExterno))
                {
                    presupuestoProduccion.DestinoId = ctx.DbDestinoes.Where(t => t.CodigoExterno == presupuestoProduccion.DestinoCodigoExterno).Select(s => s.Id).Single();
                }

                dbPresupuestoProduccion.DestinoId = presupuestoProduccion.DestinoId;
                dbPresupuestoProduccion.EmpresaId = presupuestoProduccion.EmpresaId;
                dbPresupuestoProduccion.Aprobado = null;

                ctx.SaveChanges();

                SaveDetallePresupuestoProduccion(serviceOptions, ctx, dbPresupuestoProduccion, presupuestoProduccion.DetalleDeProductos);

                ctx.SaveChanges();

                presupuestoProduccion.Id = dbPresupuestoProduccion.Id;
            }

            return dbPresupuestoProduccion;
        }

        public PresupuestoProduccion GetPresupuestoProduccionById(ServiceOptions serviceOptions, int id)
        {
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                DbPresupuestoProduccion dbPresupuestoProduccion = ctx.DbPresupuestoProduccions.FilterLogicalRemoved().Where(p => p.Id == id).Single();

                PresupuestoProduccion presupuestoProduccion = new PresupuestoProduccion()
                                                                {
                                                                    Id = dbPresupuestoProduccion.Id,
                                                                    DestinoId = dbPresupuestoProduccion.DestinoId,
                                                                    DestinoNombre = dbPresupuestoProduccion.Destino.Nombre,
                                                                    DestinoCodigoExterno = dbPresupuestoProduccion.Destino.CodigoExterno,
                                                                    Nombre = dbPresupuestoProduccion.Nombre,
                                                                    TemporadaId = dbPresupuestoProduccion.TemporadaId,
                                                                    TemporadaNombre = dbPresupuestoProduccion.Temporada.Nombre,
                                                                    TemporadaCodigoExterno = dbPresupuestoProduccion.Temporada.Nombre,
                                                                    EmpresaId = dbPresupuestoProduccion.EmpresaId,
                                                                    ProveedorId = dbPresupuestoProduccion.ProveedorId,
                                                                    ProveedorIdExterno = dbPresupuestoProduccion.Proveedor.ProveedorIdExterno,
                                                                    ProveedorNombre = dbPresupuestoProduccion.Proveedor.RazonSocial,
                                                                    EstadoBool = dbPresupuestoProduccion.Aprobado,
                                                                    FechaAprobacion = dbPresupuestoProduccion.FechaAprobacion,
                                                                    UserNameAprobacion = dbPresupuestoProduccion.UsuarioAprobacion,
                                                                    PlanProduccionId = dbPresupuestoProduccion.PlanProduccionId,
                                                                    AuditFechaCreacion = dbPresupuestoProduccion.AuditFechaCreacion,
                                                                    AuditFechaModificacion = dbPresupuestoProduccion.AuditFechaModificacion,
                                                                    AuditUserNameCreacion = dbPresupuestoProduccion.AuditUserNameCreacion,
                                                                    AuditUserNameModificacion = dbPresupuestoProduccion.AuditUserNameModificacion
                                                                };

                presupuestoProduccion.Estado = presupuestoProduccion.EstadoBool.HasValue ? (presupuestoProduccion.EstadoBool.Value ? EstadoAprobado.Aprobado : EstadoAprobado.NoAprobado) : EstadoAprobado.NoDefinido;

                int total = 0;
                PresupuestoProduccionDetalleProd ppDetalle;
                foreach (var dbPPDetalle in dbPresupuestoProduccion.PresupuestoProduccionDetalles)
                {
                    ppDetalle = new PresupuestoProduccionDetalleProd()
                    {
                        Id = dbPPDetalle.Id,
                        PresupuestoProduccionId = dbPPDetalle.PresupuestoProduccionId,
                        ProductoId = dbPPDetalle.ProductoId,
                        ProductoIdExterno = dbPPDetalle.Producto.ProductoIdExterno,
                        ProductoNombre = dbPPDetalle.Producto.ProductoNombre,
                        CalidadId = Convert.ToInt32(dbPPDetalle.Producto.CalidadExternaId),
                        CalidadNombre = dbPPDetalle.Producto.Calidad.Descripcion,
                        ColorId = dbPPDetalle.Producto.ColorIdExterno,
                        ColorNombre = dbPPDetalle.Producto.Color.Descripcion
                    };

                    presupuestoProduccion.DetalleDeProductos.Add(ppDetalle);

                    PresupuestoProduccionDetalleProdSemanal ppDetalleCantidad;
                    foreach (var dbPPSemanaCantidad in dbPPDetalle.PresupuestoProduccionDetalleCantidades)
                    {
                        ppDetalleCantidad = new PresupuestoProduccionDetalleProdSemanal()
                        {
                            Id = dbPPSemanaCantidad.Id,
                            NumeroSemana = dbPPSemanaCantidad.NumeroSemana,
                            Cantidad = dbPPSemanaCantidad.Cantidad,
                            AuditFechaCreacion = dbPPSemanaCantidad.AuditFechaCreacion,
                            AuditFechaModificacion = dbPPSemanaCantidad.AuditFechaModificacion,
                            AuditUserNameCreacion = dbPPSemanaCantidad.AuditUserNameCreacion,
                            AuditUserNameModificacion = dbPPSemanaCantidad.AuditUserNameModificacion
                        };

                        total += dbPPSemanaCantidad.Cantidad;

                        ppDetalle.CantidadesPorSemana.Add(ppDetalleCantidad);
                    }
                }

                presupuestoProduccion.TotalPresupuesto = total;

                return presupuestoProduccion;
            }
        }

        public List<Producto> GetProductosForPresupuesto(ServiceOptions serviceOptions, string codigoProducto, string descripcionProducto, int presupuestoProduccionId, int temporadaId)
        {
            List<Producto> productoList = new List<Producto>();
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbProducto> query = ctx.DbProductoes.FilterLogicalRemoved().Where(t => t.TemporadaId == temporadaId);

                if (!String.IsNullOrEmpty(codigoProducto))
                {
                    query = query.Where(p => p.ProductoIdExterno.StartsWith(codigoProducto));
                }

                if (!String.IsNullOrEmpty(descripcionProducto))
                {
                    query = query.Where(p => p.ProductoNombre.Contains(descripcionProducto));
                }

                productoList = (from p in query
                                where !(from detalle in ctx.DbPresupuestoProduccionDetalles
                                        where detalle.PresupuestoProduccionId == presupuestoProduccionId
                                        select detalle.ProductoId).Contains(p.Id)
                                select new Producto()
                                {
                                    Id = p.Id,
                                    ProductoIdExterno = p.ProductoIdExterno,
                                    ProductoNombre = p.ProductoNombre,
                                    CalidadId = p.CalidadExternaId,
                                    Calidad = p.Calidad.Descripcion,
                                    ColorIdExterno = p.ColorIdExterno,
                                    ColorNombreExterno = p.Color.Descripcion,
                                    TemporadaCodigoExterno = p.Temporada.CodigoExterno
                                }).ToList();
            }

            return productoList;
        }

        private static string GetCalidadDesc(int calidadId)
        {
            string calidad = string.Empty;

            if (calidadId == 1)
                calidad = "Primera";
            else if (calidadId == 2)
                calidad = "Segunda";
            else
                calidad = "No especifica";

            return calidad;
        }

        public void UpdatePresupuestoProduccionItems(ServiceOptions serviceOptions, int presupuestoProduccionId, List<UpdateCantidadPlanProd> updates, List<int> deletedProductItems)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    DbPresupuestoProduccion dbPresupuestoProduccion = ctx.DbPresupuestoProduccions.Where(p => p.Id == presupuestoProduccionId).Single();

                    if (!dbPresupuestoProduccion.Aprobado.HasValue)
                    {

                        foreach (UpdateCantidadPlanProd update in updates)
                        {
                            DbPresupuestoProduccionDetalle dbPPDetalle;

                            dbPPDetalle = dbPresupuestoProduccion.PresupuestoProduccionDetalles.Where(d => d.ProductoId == update.ProductoId).SingleOrDefault();

                            if (dbPPDetalle == null)
                            {
                                dbPPDetalle = new DbPresupuestoProduccionDetalle();
                                dbPPDetalle.AuditUserNameCreacion = serviceOptions.UserName;
                                dbPPDetalle.AuditFechaCreacion = DateTime.Now;
                                dbPresupuestoProduccion.PresupuestoProduccionDetalles.Add(dbPPDetalle);
                            }
                            else
                            {
                                dbPPDetalle = dbPresupuestoProduccion.PresupuestoProduccionDetalles.Where(p => p.Id == update.Id).Single();
                                dbPPDetalle.AuditUserNameModificacion = serviceOptions.UserName;
                                dbPPDetalle.AuditFechaModificacion = DateTime.Now;
                            }

                            dbPPDetalle.ProductoId = update.ProductoId;

                            DbPresupuestoProduccionDetalleCantidade cantSemanal = dbPPDetalle.PresupuestoProduccionDetalleCantidades.Where(c => c.NumeroSemana == update.NumeroSemana).SingleOrDefault();
                            if (cantSemanal == null)
                            {
                                cantSemanal = new DbPresupuestoProduccionDetalleCantidade();
                                cantSemanal.NumeroSemana = update.NumeroSemana;
                                cantSemanal.AuditUserNameCreacion = serviceOptions.UserName;
                                cantSemanal.AuditFechaCreacion = DateTime.Now;
                                dbPPDetalle.PresupuestoProduccionDetalleCantidades.Add(cantSemanal);
                            }
                            else
                            {
                                cantSemanal.AuditUserNameModificacion = serviceOptions.UserName;
                                cantSemanal.AuditFechaModificacion = DateTime.Now;
                            }

                            cantSemanal.Cantidad = update.Cantidad;
                        }

                        foreach (int idProdToRemove in deletedProductItems)
                        {
                            var detalleToRemove = dbPresupuestoProduccion.PresupuestoProduccionDetalles.Where(d => d.Id == idProdToRemove).SingleOrDefault();
                            if (detalleToRemove != null)
                            {
                                DbPresupuestoProduccionDetalleCantidade dbDetalleCantidad;
                                while (detalleToRemove.PresupuestoProduccionDetalleCantidades.Count > 0)
                                {
                                    dbDetalleCantidad = detalleToRemove.PresupuestoProduccionDetalleCantidades.First();
                                    ctx.DbPresupuestoProduccionDetalleCantidades.DeleteObject(dbDetalleCantidad);
                                }

                                detalleToRemove.PresupuestoProduccionDetalleCantidades.Clear();

                                ctx.DbPresupuestoProduccionDetalles.DeleteObject(detalleToRemove);
                            }
                        }

                        ctx.SaveChanges();
                    }
                }

                tScope.Complete();
            }
        }

      
        public List<PlanProduccion> GetPlanProduccion(ServiceOptions serviceOptions, int? planProduccionId, string nombreLike, int? temporadaId, int? destinoId, int? proveedorId, DateTime? fechaDesde, DateTime? fechaHasta)
        {
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbPlanProduccion> query = ctx.DbPlanProduccions.FilterLogicalRemoved();

                if (planProduccionId.HasValue)
                {
                    query = query.Where(p => p.Id == planProduccionId.Value);
                }
                else
                {
                    if (!String.IsNullOrEmpty(nombreLike))
                    {
                        query = query.Where(p => p.Nombre.Contains(nombreLike));
                    }

                    if (temporadaId.HasValue)
                    {
                        query = query.Where(p => p.TemporadaId == temporadaId.Value);
                    }
                    if (destinoId.HasValue)
                    {
                        query = query.Where(p => p.DestinoId == destinoId.Value);
                    }

                    if (proveedorId.HasValue)
                    {
                        query = query.Where(p => p.ProveedorId == proveedorId.Value);
                    }

                    if (fechaDesde.HasValue)
                    {
                        query = query.Where(p => p.AuditFechaModificacion.Value >= fechaDesde.Value);
                    }
                    if (fechaHasta.HasValue)
                    {
                        query = query.Where(p => p.AuditFechaModificacion.Value <= fechaHasta.Value);
                    }
                }

                if (!serviceOptions.IsAdmin)
                {
                    query = query.Where(d => serviceOptions.Operations.Contains(d.Destino.SecurityKey));
                }

                query = query.OrderBy(p => p.Id);

                if (serviceOptions != null && serviceOptions.UsePages)
                {
                    query = query.Skip(serviceOptions.GetSkip()).Take(serviceOptions.PageSize);
                }

                List<PlanProduccion> planesDeProduccion = new List<PlanProduccion>();
                planesDeProduccion.AddRange((from p in query
                                             select new PlanProduccion()
                                                {
                                                    Id = p.Id,
                                                    Nombre = p.Nombre,
                                                    DestinoId = p.DestinoId,
                                                    DestinoNombre = p.Destino.Nombre,
                                                    TemporadaId = p.TemporadaId,
                                                    TemporadaNombre = p.Temporada.Nombre,
                                                    EmpresaId = p.EmpresaId,
                                                    SincronizaSJ = p.SincronizaSJ,
                                                    ProveedorId = p.ProveedorId,
                                                    ProveedorNombre = p.Proveedor.RazonSocial,
                                                    AuditFechaCreacion = p.AuditFechaCreacion,
                                                    AuditFechaModificacion = p.AuditFechaModificacion,
                                                    AuditUserNameCreacion = p.AuditUserNameCreacion,
                                                    AuditUserNameModificacion = p.AuditUserNameModificacion
                                                }).ToList());
                return planesDeProduccion;
            }
        }

        public void EliminarPlanProduccion(ServiceOptions serviceOptions, int planProduccionId)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    DateTime dateTimeNow = DateTime.Now;
                    // Elimino el plan
                    var planProduccion = ctx.DbPlanProduccions.Where(d => d.Id == planProduccionId).Single();
                    planProduccion.Removed = true;
                    planProduccion.AuditFechaModificacion = dateTimeNow;
                    planProduccion.AuditUserNameModificacion = serviceOptions.UserName;

                    // Elimino los presupuestos
                    foreach (var presupuesto in planProduccion.PresupuestoProduccions)
                    {
                        presupuesto.Removed = true;
                        presupuesto.AuditFechaModificacion = dateTimeNow;
                        presupuesto.AuditUserNameModificacion = serviceOptions.UserName;
                    }

                    // elimino el detalle del plan
                    foreach (var planProduccionDetalle in planProduccion.PlanProduccionDetalles)
                    {
                        // elimino los desvios
                        foreach (var dbPlanProdDesvio in planProduccionDetalle.PlanProdDesvios)
                        {
                            dbPlanProdDesvio.Removed = true;
                            dbPlanProdDesvio.AuditFechaModificacion = dateTimeNow;
                            dbPlanProdDesvio.AuditUserNameModificacion = serviceOptions.UserName;
                        }

                        planProduccionDetalle.Removed = true;
                        planProduccionDetalle.AuditFechaModificacion = dateTimeNow;
                        planProduccionDetalle.AuditUserNameModificacion = serviceOptions.UserName;
                    }

                    ctx.SaveChanges();
                }

                tScope.Complete();
            }
        }

        public void UpdatePlanProduccionDetalle(ServiceOptions serviceOptions, List<PlanProduccionDetalleProd> planProduccionDetalles)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    if (planProduccionDetalles.Count() > 0)
                    {
                        int planProduccionId = planProduccionDetalles.First().PlanProduccionId;
                        DbPlanProduccion dbPlanProduccion = ctx.DbPlanProduccions.Where(p => p.Id == planProduccionId).Single();

                        SaveDetallePlanProduccion(serviceOptions, ctx, dbPlanProduccion, planProduccionDetalles);

                        ctx.SaveChanges();
                    }
                }

                tScope.Complete();
            }
        }

        private void SaveDetallePlanProduccion(ServiceOptions serviceOptions, PlanProdEntities ctx, DbPlanProduccion dbPlanProduccion, List<PlanProduccionDetalleProd> planProduccionDetalles)
        {
            // Elimino todo lo que habia
            DbPlanProduccionDetalle dbDetalle;
            while (dbPlanProduccion.PlanProduccionDetalles.Count > 0)
            {
                dbDetalle = dbPlanProduccion.PlanProduccionDetalles.First();
                DbPlanProduccionDetalleCantidade dbDetalleCantidad;
                while (dbDetalle.PlanProduccionDetalleCantidades.Count > 0)
                {
                    dbDetalleCantidad = dbDetalle.PlanProduccionDetalleCantidades.First();
                    ctx.DbPlanProduccionDetalleCantidades.DeleteObject(dbDetalleCantidad);
                }

                dbDetalle.PlanProduccionDetalleCantidades.Clear();

                ctx.DbPlanProduccionDetalles.DeleteObject(dbDetalle);
            }

            dbPlanProduccion.PlanProduccionDetalles.Clear();

            ctx.SaveChanges();

            // Cargo lo nuevo
            foreach (PlanProduccionDetalleProd ppProd in planProduccionDetalles)
            {
                DbPlanProduccionDetalle dbPPDetalle = new DbPlanProduccionDetalle();
                dbPPDetalle.AuditFechaCreacion = DateTime.Now;
                dbPPDetalle.AuditUserNameCreacion = serviceOptions.UserName;
                // Encontrar el producto

                dbPPDetalle.ProductoId = GetProductoIdFromProductoColor(ctx, ppProd.ProductoIdExterno, ppProd.ColorIdExterno);
                //ctx.DbPlanProduccionDetalles.AddObject(dbPPDetalle);

                dbPlanProduccion.PlanProduccionDetalles.Add(dbPPDetalle);

                foreach (PlanProduccionDetalleProdSemanal ppProdCantSemana in ppProd.CantidadesPorSemana)
                {
                    DbPlanProduccionDetalleCantidade dbCantidadPorSemana = new DbPlanProduccionDetalleCantidade();
                    dbCantidadPorSemana.NumeroSemana = ppProdCantSemana.NumeroSemana;
                    dbCantidadPorSemana.Cantidad = ppProdCantSemana.Cantidad;
                    dbCantidadPorSemana.AuditFechaCreacion = DateTime.Now;
                    dbCantidadPorSemana.AuditUserNameCreacion = serviceOptions.UserName;
                    dbPPDetalle.PlanProduccionDetalleCantidades.Add(dbCantidadPorSemana);
                }
            }
        }

        public void MarcarPlanProduccionParaSanJuan(ServiceOptions serviceOptions, int planProduccionId, bool sincronizaSJ)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    DbPlanProduccion dbPlanProduccion = ctx.DbPlanProduccions.Where(p => p.Id == planProduccionId).SingleOrDefault();

                    if (dbPlanProduccion != null)
                    {
                        dbPlanProduccion.SincronizaSJ = sincronizaSJ;
                        ctx.SaveChanges();
                        tScope.Complete();
                    }
                }
            }
        }

        public PlanProduccion SavePlanProduccion(ServiceOptions serviceOptions, PlanProduccion planProduccion)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    DbPlanProduccion dbPlanProduccion = ctx.DbPlanProduccions.Where(p => p.Id == planProduccion.Id).SingleOrDefault();

                    if (dbPlanProduccion == null)
                    {
                        dbPlanProduccion = new DbPlanProduccion();
                        dbPlanProduccion.AuditUserNameCreacion = serviceOptions.UserName;
                        dbPlanProduccion.AuditFechaCreacion = DateTime.Now;
                        ctx.DbPlanProduccions.AddObject(dbPlanProduccion);
                    }
                    else
                    {
                        dbPlanProduccion.AuditUserNameModificacion = serviceOptions.UserName;
                        dbPlanProduccion.AuditFechaModificacion = DateTime.Now;
                    }

                    dbPlanProduccion.Nombre = planProduccion.Nombre;
                    dbPlanProduccion.TemporadaId = planProduccion.TemporadaId;
                    dbPlanProduccion.ProveedorId = planProduccion.ProveedorId;
                    dbPlanProduccion.DestinoId = planProduccion.DestinoId;
                    dbPlanProduccion.EmpresaId = planProduccion.EmpresaId;
                    dbPlanProduccion.SincronizaSJ = planProduccion.SincronizaSJ;

                    ctx.SaveChanges();

                    SaveDetallePlanProduccion(serviceOptions, ctx, dbPlanProduccion, planProduccion.DetalleDeProductos);

                    ctx.SaveChanges();

                    planProduccion.Id = dbPlanProduccion.Id;

                }

                tScope.Complete();
                return planProduccion;
            }
        }

        public PlanProduccion GetPlanProduccionById(ServiceOptions serviceOptions, int id, List<int> detalleIds)
        {
            if (detalleIds == null)
            {
                detalleIds = new List<int>();
            }

            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                DbPlanProduccion dbPlanProduccion = ctx.DbPlanProduccions.FilterLogicalRemoved().Where(p => p.Id == id).Single();

                PlanProduccion planProduccion = new PlanProduccion()
                {
                    Id = dbPlanProduccion.Id,
                    Nombre = dbPlanProduccion.Nombre,
                    DestinoId = dbPlanProduccion.DestinoId,
                    DestinoNombre = dbPlanProduccion.Destino.Nombre,
                    TemporadaId = dbPlanProduccion.TemporadaId,
                    TemporadaNombre = dbPlanProduccion.Temporada.Nombre,
                    EmpresaId = dbPlanProduccion.EmpresaId,
                    SincronizaSJ = dbPlanProduccion.SincronizaSJ,
                    ProveedorId = dbPlanProduccion.ProveedorId,
                    ProveedorNombre = dbPlanProduccion.Proveedor.RazonSocial,
                    PresupuestoProduccionId = dbPlanProduccion.PresupuestoProduccions.First().Id,
                    AuditFechaCreacion = dbPlanProduccion.AuditFechaCreacion,
                    AuditFechaModificacion = dbPlanProduccion.AuditFechaModificacion,
                    AuditUserNameCreacion = dbPlanProduccion.AuditUserNameCreacion,
                    AuditUserNameModificacion = dbPlanProduccion.AuditUserNameModificacion
                };

                int total = 0;
                PlanProduccionDetalleProd ppDetalle;
                bool loadDetalle = true;
                foreach (var dbPPDetalle in dbPlanProduccion.PlanProduccionDetalles)
                {
                    if (detalleIds.Count > 0)
                    {
                        loadDetalle = detalleIds.Where(di => di == dbPPDetalle.Id).Count() > 0;
                    }
                    else
                    {
                        loadDetalle = true;
                    }

                    if (loadDetalle)
                    {
                        ppDetalle = new PlanProduccionDetalleProd()
                        {
                            Id = dbPPDetalle.Id,
                            PlanProduccionId = dbPPDetalle.PlanProduccionId,
                            ProductoId = dbPPDetalle.ProductoId,
                            ProductoIdExterno = dbPPDetalle.Producto.ProductoIdExterno,
                            ProductoNombre = dbPPDetalle.Producto.ProductoNombre,
                            CalidadId = Convert.ToInt32(dbPPDetalle.Producto.CalidadExternaId),
                            Calidad = dbPPDetalle.Producto.Calidad.Descripcion,
                            ColorIdExterno = dbPPDetalle.Producto.ColorIdExterno,
                            ColorNombreExterno = dbPPDetalle.Producto.Color.Descripcion,
                        };

                        ppDetalle.ProductoSegundaId = dbPPDetalle.Producto.ProductoSegundaId;

                        string estadoDesvioStr = Convert.ToString((char)EstadoCharAprobado.EsperandoAprobacion);
                        ppDetalle.DesvioPendienteDeAprobacion = dbPPDetalle.PlanProdDesvios.Where(d => d.Estado == estadoDesvioStr).Count() > 0;

                        planProduccion.DetalleDeProductos.Add(ppDetalle);

                        PlanProduccionDetalleProdSemanal ppDetalleCantidad;
                        foreach (var dbPPSemanaCantidad in dbPPDetalle.PlanProduccionDetalleCantidades)
                        {
                            ppDetalleCantidad = new PlanProduccionDetalleProdSemanal()
                            {
                                Id = dbPPSemanaCantidad.Id,
                                NumeroSemana = dbPPSemanaCantidad.NumeroSemana,
                                Cantidad = dbPPSemanaCantidad.Cantidad,
                                AuditFechaCreacion = dbPPSemanaCantidad.AuditFechaCreacion,
                                AuditFechaModificacion = dbPPSemanaCantidad.AuditFechaModificacion,
                                AuditUserNameCreacion = dbPPSemanaCantidad.AuditUserNameCreacion,
                                AuditUserNameModificacion = dbPPSemanaCantidad.AuditUserNameModificacion
                            };

                            total += dbPPSemanaCantidad.Cantidad;

                            ppDetalle.CantidadesPorSemana.Add(ppDetalleCantidad);
                        }
                    }
                }

                planProduccion.TotalPlan = total;

                return planProduccion;
            }
        }

        public List<Producto> GetProductosForPlan(ServiceOptions serviceOptions, string filter, int planProduccionId)
        {
            List<Producto> productoList = new List<Producto>();
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbProducto> query = ctx.DbProductoes.FilterLogicalRemoved();

                if (!String.IsNullOrEmpty(filter))
                {
                    query = query.Where(p => p.ProductoNombre.Contains(filter));
                }

                query = query.OrderBy(p => p.Id);

                if (serviceOptions != null && serviceOptions.UsePages)
                {
                    query = query.Skip(serviceOptions.GetSkip()).Take(serviceOptions.PageSize);
                }

                productoList = (from p in query
                                where (from detalle in ctx.DbPlanProduccionDetalles
                                       where detalle.PlanProduccionId == planProduccionId
                                       select detalle.ProductoId).Contains(p.Id)
                                select new Producto()
                                {
                                    Id = p.Id,
                                    ProductoIdExterno = p.ProductoIdExterno,
                                    ProductoNombre = p.ProductoNombre,
                                    CalidadId = p.CalidadExternaId,
                                    Calidad = p.Calidad.Descripcion,
                                    ColorIdExterno = p.ColorIdExterno,
                                    ColorNombreExterno = p.Color.Descripcion,
                                    TemporadaCodigoExterno = p.TemporadaLetra
                                }).ToList();
            }

            return productoList;
        }

        public SearchProductResult SearchProducts(ServiceOptions serviceOptions, SearchProductCriteria criteria)
        {
            SearchProductResult result = new SearchProductResult();
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbProducto> query = ctx.DbProductoes;

                if (criteria.Id.HasValue)
                {
                    query = query.Where(p => p.Id == criteria.Id.Value);
                }
                else
                {
                    query = query.Where(p => p.EmpresaId == criteria.EmpresaId);

                    if (!String.IsNullOrEmpty(criteria.CodigoProducto))
                    {
                        query = query.Where(p => p.ProductoIdExterno.StartsWith(criteria.CodigoProducto));
                    }

                    if (!String.IsNullOrEmpty(criteria.CodigoColor))
                    {
                        query = query.Where(p => p.ColorIdExterno == criteria.CodigoColor);
                    }

                    if (criteria.TemporadaId.HasValue)
                    {
                        query = query.Where(p => p.TemporadaId == criteria.TemporadaId.Value);
                    }

                    if (criteria.CalidadId.HasValue)
                    {
                        string calidadStr = criteria.CalidadId.Value.ToString();
                        query = query.Where(p => p.CalidadExternaId == calidadStr);
                    }

                    if (criteria.FechasincDesde.HasValue)
                    {
                        query = query.Where(p => p.FechaSincronizacion >= criteria.FechasincDesde.Value);
                    }

                    if (criteria.FechasincHasta.HasValue)
                    {
                        DateTime fechaHasta = criteria.FechasincHasta.Value.Date.AddDays(1).AddSeconds(-1);
                        query = query.Where(p => p.FechaSincronizacion <= fechaHasta);
                    }
                }

                result.Count = query.Count();

                if (!criteria.SoloContar)
                {
                    query = query.OrderBy(p => p.ProductoIdExterno);

                    if (criteria.PageSize != 0)
                    {
                        query = query.Skip(criteria.PageSkip).Take(criteria.PageSize);
                    }

                    foreach (var p in query.ToList())
                    {
                        Producto prod = new Producto();

                        prod.Id = p.Id;
                        prod.ProductoIdExterno = p.ProductoIdExterno;
                        prod.ProductoNombre = p.ProductoNombre;                        

                        prod.CalidadId = p.CalidadExternaId;
                        if (p.Calidad != null)
                            prod.Calidad = p.Calidad.Descripcion;
                        prod.ColorIdExterno = p.ColorIdExterno;
                        if (p.Color != null)
                            prod.ColorNombreExterno = p.Color.Descripcion;
                        if (p.Temporada != null)
                        {
                            prod.TemporadaCodigoExterno = p.Temporada.CodigoExterno;
                            prod.TemporadaNombre = p.Temporada.Nombre;
                        }

                        prod.RubroId = p.RubroId;
                        if (p.Rubro != null)
                            prod.RubroNombre = p.Rubro.Nombre;
                        prod.MarcaIdExterno = p.MarcaIdExterno;
                        if (p.Marca != null)
                            prod.MarcaNombreExterno = p.Marca.Descripcion;
                        prod.OrigenIdExterno = p.OrigenIdExterno;
                        if (p.Origen != null)
                            prod.OrigenNombreExterno = p.Origen.Descripcion;
                        prod.LineaIdExterno = p.LineaIdExterno;
                        if (p.Linea != null)
                            prod.LineaNombreExterno = p.Linea.Descripcion;
                        prod.FamiliaIdExterno = p.FamiliaIdExterno;
                        if (p.Categoria != null)
                            prod.FamiliaNombreExterno = p.Categoria.Descripcion;
                        prod.SubFamiliaIdExterno = p.SubFamiliaIdExterno;
                        if (p.SubCategoria != null)
                            prod.SubFamiliaNombreExterno = p.SubCategoria.Descripcion;
                        prod.GrupoTalleIdExterno = p.GrupoTalleId;
                        if (p.GrupoTalle != null)
                            prod.GrupoTalleNombreExterno = p.GrupoTalle.Descripcion;
                        prod.CodigoOrly = p.CodigoOrly;
                        prod.FechaSincronizacion = p.FechaSincronizacion;

                        if (!string.IsNullOrEmpty(p.ProductoSegundaIdExterno))
                        {
                            prod.ProductoIdExternoSegunda = p.ProductoSegundaIdExterno;
                        }

                        result.Productos.Add(prod);
                    }
                }
            }

            return result;
        }

        public List<Producto> GetPossibleProductosForPlan(ServiceOptions serviceOptions, string filter, int planProduccionId)
        {
            List<Producto> productoList = new List<Producto>();
            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                IQueryable<DbProducto> query = ctx.DbProductoes.FilterLogicalRemoved();

                if (!String.IsNullOrEmpty(filter))
                {
                    query = query.Where(p => p.ProductoNombre.Contains(filter));
                }

                query = query.OrderBy(p => p.ProductoIdExterno);

                if (serviceOptions != null && serviceOptions.UsePages)
                {

                    query = query.Skip(serviceOptions.GetSkip()).Take(serviceOptions.PageSize);
                }

                productoList = (from p in query
                                where !(from detalle in ctx.DbPlanProduccionDetalles
                                        where detalle.PlanProduccionId == planProduccionId
                                        select detalle.ProductoId).Contains(p.Id)
                                select new Producto()
                                {
                                    Id = p.Id,
                                    ProductoIdExterno = p.ProductoIdExterno,
                                    ProductoNombre = p.ProductoNombre,
                                    CalidadId = p.CalidadExternaId,
                                    Calidad = p.Calidad.Descripcion,
                                    ColorIdExterno = p.ColorIdExterno,
                                    ColorNombreExterno = p.Color.Descripcion,
                                    TemporadaCodigoExterno = p.TemporadaLetra
                                }).ToList();
            }

            return productoList;
        }

        public void UpdatePlanProduccionItems(ServiceOptions serviceOptions, int planProduccionId, List<UpdateCantidadPlanProd> updates, List<int> deletedProductItems)
        {

            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    DbPlanProduccion dbPlanProduccion = ctx.DbPlanProduccions.Where(p => p.Id == planProduccionId).Single();

                    foreach (UpdateCantidadPlanProd update in updates)
                    {
                        DbPlanProduccionDetalle dbPPDetalle;

                        dbPPDetalle = dbPlanProduccion.PlanProduccionDetalles.Where(d => d.ProductoId == update.ProductoId).SingleOrDefault();

                        if (dbPPDetalle == null)
                        {
                            dbPPDetalle = new DbPlanProduccionDetalle();
                            dbPPDetalle.AuditUserNameCreacion = serviceOptions.UserName;
                            dbPPDetalle.AuditFechaCreacion = DateTime.Now;
                            dbPlanProduccion.PlanProduccionDetalles.Add(dbPPDetalle);
                        }
                        else
                        {
                            dbPPDetalle = dbPlanProduccion.PlanProduccionDetalles.Where(p => p.Id == update.Id).Single();
                            dbPPDetalle.AuditUserNameModificacion = serviceOptions.UserName;
                            dbPPDetalle.AuditFechaModificacion = DateTime.Now;
                        }

                        dbPPDetalle.ProductoId = update.ProductoId;

                        DbPlanProduccionDetalleCantidade cantSemanal = dbPPDetalle.PlanProduccionDetalleCantidades.Where(c => c.NumeroSemana == update.NumeroSemana).SingleOrDefault();
                        if (cantSemanal == null)
                        {
                            cantSemanal = new DbPlanProduccionDetalleCantidade();
                            cantSemanal.NumeroSemana = update.NumeroSemana;
                            cantSemanal.AuditUserNameCreacion = serviceOptions.UserName;
                            cantSemanal.AuditFechaCreacion = DateTime.Now;
                            dbPPDetalle.PlanProduccionDetalleCantidades.Add(cantSemanal);
                        }
                        else
                        {
                            cantSemanal.AuditUserNameModificacion = serviceOptions.UserName;
                            cantSemanal.AuditFechaModificacion = DateTime.Now;
                        }

                        cantSemanal.Cantidad = update.Cantidad;
                    }

                    foreach (int idProdToRemove in deletedProductItems)
                    {
                        var detalleToRemove = dbPlanProduccion.PlanProduccionDetalles.Where(d => d.Id == idProdToRemove).SingleOrDefault();
                        if (detalleToRemove != null)
                        {
                            DbPlanProduccionDetalleCantidade dbDetalleCantidad;
                            while (detalleToRemove.PlanProduccionDetalleCantidades.Count > 0)
                            {
                                dbDetalleCantidad = detalleToRemove.PlanProduccionDetalleCantidades.First();
                                ctx.DbPlanProduccionDetalleCantidades.DeleteObject(dbDetalleCantidad);
                            }

                            detalleToRemove.PlanProduccionDetalleCantidades.Clear();

                            ctx.DbPlanProduccionDetalles.DeleteObject(detalleToRemove);
                        }
                    }

                    ctx.SaveChanges();
                }

                tScope.Complete();
            }
        }

        /// <summary>
        /// Solo da de alta productos, no los actualiza
        /// </summary>
        /// <param name="serviceOptions"></param>
        /// <param name="productoList"></param> 
        public void SaveProductos(ServiceOptions serviceOptions, List<Producto> productoList)
        {
            using (TransactionScope tScope = CreateTransactionScope())
            {
                using (PlanProdEntities ctx = new PlanProdEntities())
                {
                    foreach (Producto producto in productoList)
                    {
                        // TODO: Tengo que verificar que existan las relaciones, sino las creo

                        DbProducto dbProducto = new DbProducto();
                        dbProducto.ProductoIdExterno = producto.ProductoIdExterno;
                        dbProducto.ColorIdExterno = producto.ColorIdExterno;
                        dbProducto.ProductoNombre = producto.ProductoNombre;
                        dbProducto.TemporadaLetra = producto.TemporadaCodigoExterno;
                        dbProducto.MarcaIdExterno = producto.MarcaIdExterno;
                        dbProducto.OrigenIdExterno = producto.OrigenIdExterno;
                        dbProducto.LineaIdExterno = producto.LineaIdExterno;
                        dbProducto.FamiliaIdExterno = producto.FamiliaIdExterno;
                        dbProducto.SubFamiliaIdExterno = producto.SubFamiliaIdExterno;
                        dbProducto.ProductoSegundaIdExterno = producto.ProductoIdExternoSegunda;
                        dbProducto.RubroId = producto.ProductoIdExterno.Substring(2, 1);
                        dbProducto.AuditUserNameCreacion = serviceOptions.UserName;
                        dbProducto.AuditFechaCreacion = DateTime.Now;
                        dbProducto.EmpresaId = producto.EmpresaId;

                        ctx.DbProductoes.AddObject(dbProducto);
                    }

                    ctx.SaveChanges();

                    ctx.ActualizarIngresoDeProductos();

                    tScope.Complete();
                }
            }
        }

        private static string FormatearCodigoProveedorParaSincronizarSapRemover(string codigoProveedor)
        {
            //"0000000004"
            int i = 0;
            for(i = 0; i < codigoProveedor.Length; i++)
            {
                if (codigoProveedor[i] != '0')
                    break;
            }

            return codigoProveedor.Substring(i, codigoProveedor.Length - i);
        }

        private static string FormatearCodigoProveedorParaSincronizarSapCompletar(string codigoProveedor)
        {
            //"0000000004"            
            codigoProveedor = string.Concat("0000000000", codigoProveedor);

            return codigoProveedor.Substring(codigoProveedor.Length - 10, 10);
        }

        public List<Proveedor> SincronizarProveedores(ServiceOptions serviceOptions, Proveedor proveedor)
        {
            List<Proveedor> proveedores = new List<Proveedor>();
            ZWS_PROVEEDORClient client = new ZWS_PROVEEDORClient();

            try
            {
                client.ClientCredentials.UserName.UserName = "gaci";
                client.ClientCredentials.UserName.Password = "gacivesuvio";

                // Empresa
                //-	1 = Lacoste
                //-	2 = Paula
                //-	5 = Penguin
                //-	4 = Cacharel

                string empresa = "1";                                            

                ZWS_PROVEEDORES_OUTLINE[] SapProveedores = new ZWS_PROVEEDORES_OUTLINE[3000];
                // El segundo string es el código
                string codigoParaBuscar = FormatearCodigoProveedorParaSincronizarSapCompletar(proveedor.ProveedorIdExterno.ToString());
                client.ZWS_PROVEEDOR(empresa, "3000", string.Empty, codigoParaBuscar, out SapProveedores);
                //client.ZWS_PROVEEDOR(empresa, "3000", string.Empty, string.Empty, out SapProveedores);

                using (TransactionScope tScope = CreateTransactionScope())
                {
                    using (PlanProdEntities ctx = new PlanProdEntities())
                    {
                        foreach (var sapProveedor in SapProveedores)
                        {
                            string sapProveedorId = FormatearCodigoProveedorParaSincronizarSapRemover(sapProveedor.PROVEEDOR);
                            int sapProvedorIdInt = Convert.ToInt32(sapProveedorId);
                            DbProveedor dbProveedor = ctx.DbProveedors.Where(p => p.ProveedorIdExterno == sapProvedorIdInt).SingleOrDefault();
                            if (dbProveedor == null)
                            {
                                dbProveedor = new DbProveedor();
                                ctx.DbProveedors.AddObject(dbProveedor);
                                dbProveedor.ProveedorIdExterno = sapProvedorIdInt;
                                dbProveedor.EmpresaId = serviceOptions.CompanyId;
                                dbProveedor.AuditUserNameCreacion = serviceOptions.UserName;
                                dbProveedor.AuditFechaCreacion = DateTime.Now;
                            }

                            dbProveedor.RazonSocial = sapProveedor.NAME1;

                            ctx.SaveChanges();

                            Proveedor tmpProveedor = new Proveedor();
                            EntityMapper.Map(dbProveedor, tmpProveedor);
                            proveedores.Add(tmpProveedor);                               
                        }
                    }

                    tScope.Complete();
                }
            }
            finally
            {
                client.Close();
            }

            return proveedores;
        }
    }
}
